Is it possible to save a Type (using "typeof()") in an enum?

C#TypesEnumsType Conversion

C# Problem Overview


So I'm creating a game in XNA, C# 4.0, and I need to manage a lot of PowerUps (which in code are all inherited from class "PowerUp"), and to handle back-end management of the PowerUps I currently have an enum, PowerupEffectType, with a value for each child class of PowerUp. Eventually in the code I need to do conversions from PowerupEffectType to the Powerup type (of class Type, achieved usually with typeof([class name])).

Since this is a group project, I want to marry each value of PowerupEffectType to its corresponding class Type as well as possible, i.e.: Not just expect my other programmers to use switch statements to do the conversion manually, and making sure additions/expansions later involve as few changes in as few places as possible. I have a few options for this, and the best I've discovered so far is creating enum pseudo-methods that condense everything down to a single switch statement (99% of what I want), thanks to some tips I found here: http://msdn.microsoft.com/en-us/library/bb383974.aspx

But I'm trying to take it one step further - can I save a Type in an enum? I know you can save enums as a specific type (link: http://msdn.microsoft.com/en-us/library/cc138362.aspx), but Type isn't one of them. The current choices are byte, sbyte, short, ushort, int, uint, long, and ulong. Is there any feasible way to save a convert a Type to any of the above data types and back?

Just to be clear, this is what I WISH I could do, and I'm looking for a way to do:

// (Assuming 'LightningPowerup', 'FirePowerup', and 'WaterPowerup' are
// all declared classes that inherit from a single base class)

public enum PowerupEffectType
{
    LIGHTNING = typeof(LightningPowerup),
    FIRE = typeof(FirePowerup),
    WATER = typeof(WaterPowerup)
}

Is there any way to do this, or am I just overcomplicating a solution to a problem that's already 99% complete?

Thanks in advance!

C# Solutions


Solution 1 - C#

You can't do it as the value of an enum, but you could specify it in an attribute:

using System;
using System.Runtime.CompilerServices;

[AttributeUsage(AttributeTargets.Field)]
public class EffectTypeAttribute : Attribute
{
    public Type Type { get; private set; }
    
    public EffectTypeAttribute(Type type)
    {
        this.Type = type;
    }
}

public class LightningPowerup {}
public class FirePowerup {}
public class WaterPowerup {}

public enum PowerupEffectType
{
    [EffectType(typeof(LightningPowerup))]
    Lightning,
    [EffectType(typeof(FirePowerup))]
    Fire,
    [EffectType(typeof(WaterPowerup))]
    Water
}

You can then extract those attribute values at execution time with reflection. However, I would personally just create a dictionary:

private static Dictionary<PowerupEffectType, Type> EffectTypeMapping =
    new Dictionary<PowerupEffectType, Type>
{
    { PowerupEffectType.Lightning, typeof(LightningPowerup) },
    { PowerupEffectType.Fire, typeof(FirePowerup) },
    { PowerupEffectType.Water, typeof(WaterPowerup) }
};

No need for a special attribute, no need to extract the values with fiddly reflection code.

Solution 2 - C#

This is not exactly what u are asking for. I find Jon's attribute method the best. But why not wrap it in an extension method?

public Type GetPowerupEffectType(this PowerupEffectType powerEffect)
{
    switch (powerEffect)
    {
        case LIGHTNING:
            return typeof(LightningPowerup);
        case FIRE:
            return typeof(FirePowerup);
        case WATER:
            return typeof(WaterPowerup);
        default:
            return default(Type);
    }
}

And call it:

PowerupEffectType e = PowerupEffectType.WATER;
var t = e.GetPowerupEffectType();

Solution 3 - C#

How about something like this?

You get the type-safety that you do with an enum, plus implicit conversion to Type

public class PowerupEffectType
{
    private readonly Type _powerupType;

    public static implicit operator Type(PowerupEffectType powerupEffectType)
    {
        return powerupEffectType._powerupType;
    }

    private PowerupEffectType(Type powerupType)
    {
        _powerupType = powerupType;
    }

    public static readonly PowerupEffectType LIGHTNING = new PowerupEffectType(typeof(LightningPowerup));
    public static readonly PowerupEffectType FIRE = new PowerupEffectType(typeof(FirePowerup));
    public static readonly PowerupEffectType WATER = new PowerupEffectType(typeof(WaterPowerup));
}

Solution 4 - C#

You could use a static Dictionary<PowerupEffectType, Powerup>. I believe that would be the kind of "marriage" you are looking for. It would allow easy enumeration and access.

Solution 5 - C#

You could use only numeric types as by documentation of Microsoft. By default the underlying type of each element in the enum is int. You can specify another integral numeric type by using a colon, as shown in the previous example. For a full list of possible types, see enum. Reference: Enumeration Types

Solution 6 - C#

Sorry, I don't quite follow this, what are you actually trying to achieve; could you give a code excerpt? I'm not sure why you can't just use inheritance here and what an enumeration gives you that type inheritance doesn't. It feels to me like you're presenting the solution rather than the problem, I may be completely wrong, could you clarify how you're planning to use this meta-information?

I'm confused, are you asking for something that tells you the type of an instance of a type/class? You can use an enumeration to store a list of the types of each type that you say, but why do you want to? You say you don't want to have the other programmers use switch statements, but I'm sorry I can't see what benefit you're getting from storing the type information in some enumeration of... the type. Every instance knows what type it is and what it can do.

What will you do with the type information? If the types all inherit from a base type, then presumably they have common functionality that can be specified in an abstract method for any special-case handling, or perhaps return a Null Object where there's nothing to do (or maybe just do nothing). This way you don't need to worry about adding new classes- as they must have the necessary behaviour. I try to avoid Enums except in situations where you're actually enumerating a fixed set of arbitrary values, they are inflexible. Enums have to be maintained, which is very difficult (in practice).

Solution 7 - C#

I actually think you might want to take a look at a dependency injection framework.

It looks like you are trying to have other developers work on different components and then you are trying to integrate them all at the end in one central location in the code base.

A few projects to look at:

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKeithA45View Question on Stackoverflow
Solution 1 - C#Jon SkeetView Answer on Stackoverflow
Solution 2 - C#nawfalView Answer on Stackoverflow
Solution 3 - C#mlorbetskeView Answer on Stackoverflow
Solution 4 - C#benjer3View Answer on Stackoverflow
Solution 5 - C#AdilView Answer on Stackoverflow
Solution 6 - C#nicodemus13View Answer on Stackoverflow
Solution 7 - C#WilView Answer on Stackoverflow