Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you add to an enum type in run-time

Tags:

c#

enums

runtime

If I have an enum type:

public enum Sport
{
    Tennis = 0;
    Football = 1;
    Squash = 2;
    Volleyball = 3;
}

Can I somehow add during run-time:

PingPong = 4
like image 707
CJ7 Avatar asked May 06 '10 08:05

CJ7


People also ask

Can you add to enum at runtime?

No, you cannot modify types at runtime.

Can you add values to enum?

You cannot create an object of an enum explicitly so, you need to add a parameterized constructor to initialize the value(s). The initialization should be done only once. Therefore, the constructor must be declared private or default. To returns the values of the constants using an instance method(getter).

Can enum value be changed?

Enum constants are implicitly static and final and you can not change their value once created.

Can you change the value of an enum in C#?

You can't do this, it is a strongly-typed value, if you like. The elements of the enum are read-only and changing them at runtime is not possible, nor would it be desirable.


3 Answers

The enum has a backing store, defaulting to int if you don't specify it. It is possible to directly assign values outside of the defined values:

Sport pingPong = (Sport)4;

Then you can check for it:

if (value == (Sport)4) {}

That is why you have the static function Enum.IsDefined() for checking if the actual value falls inside the expected values. Note that the function doesn't work for compound flag values.

bool isValueDefined = Enum.IsDefined(typeof(Sport), value);

EDIT: After Hans Passant's comment: You don't have to use the literal value 4. You could use anything which returns an int. For example:

Dictionary<int, string> AdditionalSports = new Dictionary<int, string>();
AdditionalSports.Add(4, "PingPong");

// Usages: if
if (AdditionalSports.ContainsKey(value))
{
    // Maybe do something with AdditionalSports[value], i.e. "PingPong"
}

// In a switch:
switch (value)
{
case default:
    // Since it won't be found in the enum-defined values
    if (AdditionalSports.ContainsKey(value))
    {
        // Maybe do something with AdditionalSports[value], i.e. "PingPong"
    }
}
like image 170
Daniel Rose Avatar answered Sep 28 '22 04:09

Daniel Rose


Here is more Object orientated way to maybe achieve what you are trying to achieve. This solution is inspired by early Java approach to enumeration:

struct Sport {
    readonly int value;
    public Sport(int value) {
        this.value = value;
    }
    public static implicit operator int(Sport sport) {
        return sport.value;
    }
    public static implicit operator Sport(int sport) {
        return new Sport(sport);
    }

    public const int Tennis =       0;
    public const int Football =     1;
    public const int Squash =       2;
    public const int Volleyball =   3;
}

//Usage:
Sport sport = Sport.Volleyball;
switch(sport) {
    case Sport.Squash:
        Console.WriteLine("I bounce really high");
        break;
}
Sport rugby = 5;
if (sport == rugby)
    Console.WriteLine("I am really big and eat a lot");

To walk through different featues of this solution.

  1. It's an immutable struct that wraps up an integer value. The value is enforced immutable by readonly keyword.

  2. The only way to create one of these structs is to call the constructor that takes the value as a parameter.

  3. implicit operator int is there so that the structure can be used in the switch bock - i.e. to make the structure convertible to int.

  4. implicit operator Sport is there so that you can assign integer values to the structure i.e. Sport rugby = 5.

  5. const values are the sports known at compile time. They can also be used as case labels.

What I would actually do

public static class Sports {
    public static readonly Sport Football = new Sport("Football");
    public static readonly Sport Tennis = new Sport("Tennis");
}

public class Sport {
    public Sport(string name) {
        Name = name;
    }
    public string Name { get; private set; }

    // override object.Equals
    public override bool Equals(object obj) {
        var other = obj as Sport;
        if(other == null) {
            return false;
        }

        return other == this;
    }

    // override object.GetHashCode
    public override int GetHashCode() {
        return Name.GetHashCode();
    }

    public static bool operator == (Sport sport1, Sport sport2) {
        if(Object.ReferenceEquals(sport1, null) && Object.ReferenceEquals(sport2 , null))
            return true;

        if(Object.ReferenceEquals(sport1, null) || Object.ReferenceEquals(sport2, null))
            return false;

        return sport1.Name == sport2.Name;
    }
    public static bool operator !=(Sport sport1, Sport sport2) {
        return !(sport1 == sport2);
    }
}

This would create a value class Sport that has a name. Depending on your application you can extend this class to provide other attributes and methods. Having this as class gives you more flexibility as you can subclass it.

Sports class provides a static collection of sports that are known at compile time. This is similar to how some .NET frameworks handle named colors (i.e. WPF). Here is the usage:

List<Sport> sports = new List<Sport>();

sports.Add(Sports.Football);
sports.Add(Sports.Tennis);
//What if the name contains spaces?
sports.Add(new Sport("Water Polo"));

var otherSport = new Sport("Other sport");

if(sports.Contains(otherSport)) {
    //Do something
}

foreach(var sport in sports) {
    if(sport == otherSport) {
        //Do Something
    } else if(sport == Sports.Football) {
        //do something else
    }
}

Once you do this, you'd find there is actuall very little need for having an enumeration as any conditional operations on the sport type can be handled within the Sport class.

EDIT Realised that my equality operator will throw a StackOverflowException I always keep forgetting to write Object.ReferenceEquals(obj,null) instead of obj==null, which will recurse infinitely.

like image 14
Igor Zevaka Avatar answered Sep 28 '22 04:09

Igor Zevaka


No, you cannot modify types at runtime. You could emit new types, but modifying existing ones is not possible.

like image 6
Darin Dimitrov Avatar answered Sep 28 '22 05:09

Darin Dimitrov