Question Run-time implementation of Enum

alikim

Member
Joined
Oct 30, 2023
Messages
15
Programming Experience
Beginner
I have a code that heavily relies on various enums.
Now I'm in a situation that these enums are stored in a database tables with ID colum for values and nvarchar for string representation of enum names.
The enum types (table names) are known at the compile time, the names and values are not.
I need to make the enum dependent code work with the values retrieved from database in a Entity Framework Core app, making as few changes as possible.

I'm trying to come up with a dynamic object that works like enum and has a similar syntax, in particular, I'd like to keep dot notation.
Below is what I came up so far. What do you think? Is there a simpler type I could use?

C#:
// to use as a common type, similar to Dictionary<Enum, string>
internal interface IEnum { }

public class SomeEnum : IEnum
{
    // to use dot notation
    static internal readonly dynamic v = new ExpandoObject();

    // to dynamically create properties from strings on v
    static readonly IDictionary<string, object?> iDict = (v as IDictionary<string, object?>)!;

    // to avoid boxing/unboxing while checking existing key/values
    static readonly Dictionary<string, int> dict = new();

    static internal void Init(Dictionary<string, int> _dict)
    {
        foreach (var (k, v) in _dict)
        {
            iDict[k] = v;
            dict[k] = v;
        }
    }

    string _name = "";
    int _value;

    internal string Name {
        get => _name;
        set
        {
            if (!dict.ContainsKey(value))
                throw new NotImplementedException($"SomeEnum.Name.set : '{value}' not present in dictionary");
            _name = value;
            _value = dict[value];
        }
    }

    internal int Value
    {
        get => _value;
        set
        {
            var name = dict.FirstOrDefault(p => p.Value == value).Key ??
                throw new NotImplementedException($"SomeEnum.Value.set : '{value}' not present in dictionary");
            _name = name;
            _value = value;
        }
    }

    internal SomeEnum(int _value)
    {
        Value = _value;
    }

    internal SomeEnum(string _name)
    {
        Name = _name;
    }

    public override string ToString() => $"Name: {Name}, Value: {Value}";
}

Example of usage:

C#:
        SomeEnum.Init(new Dictionary<string, int>
        {
            { "None", 0 },
            { "Left_Side", 1},
            { "Right_Side", 2}
        });
        
        var someEnum = new SomeEnum(SomeEnum.v.Left_Side);
        Console.WriteLine(someEnum);

        var someEnum2 = new SomeEnum(SomeEnum.v.Right_Side);

        someEnum.Value = SomeEnum.v.None;
        Console.WriteLine(someEnum);
 
Are you aware that enum support is built into EF? Is there a particular reason that you can't use that?

I know it's used to map enum values to the database, I need the opposite - to create enums from the database. I can not use syntax like:

C#:
public enum SomeEnum {
    None,
    Left_Side,
    Right_Side
}

because that needs to be known at the compile time and I pull values from DB, so I'm looking for a run-time substitute for that.
 
And what happens if the database value changes while your program is running?
 
These enums hold values like different game states, possible button states, the roster of players out of which you choose the opponents for the current game etc., so the values are not changing during the game. But, for example, if you want to add more players to the roster, you can do it via DB interface w/o recompiling the code. You can fetch and rebuild enum classes, if necessary, when a game starts.
 
Okay. So basically your database also stores configuration information as well as app data.

Unless you have self-modifying code, don't you need to know the enum names anyway at compile time? For example if a user just added a new player "Larry Bird", how will your code know to have something like:
Console.WriteLine(someEnum.v.Larry_Bird);

I would suggest that you really need to think hard whether you really need enums for some of the things that you think you need enums for, or whether what you are really looking for is simply a property of variable that is initialized from values from database.
 
Last edited:
don't you need to know the enum names anyway at compile time?

The code I'm working with uses enum types a lot as well as their value patterns but they are not specific. For example, enum Teams can have Blue team and Red team, and that list is editable. Larry Bird is in enum Roster and he can play for any Team, roster is editable. There is an enum of backgrounds and images, that are associated with teams, also editable. Association might be a Dictionary<EnumTeam, EnumBackgroundType> (editable). Button states are enum, values have a patterns like Ready_xxx or Missing_xxx, that might define if a button is disabled and the reason for it.
So you might loop thru enums and dictionaries to build list of teams, menus etc., construct UI (winforms or asp.net web app), or break down button states to apply some logic. Any enum specifics like 'Larry Bird' are not hardcoded anywhere (except in enum definition).
Right now all of the data is in enums, so when I say "editable" I mean you edit enums in the code and recompile.

I understand that I can pull all enums from the DB into dictionaries <string, int>, rewrite the whole code and be done with it.
But I'm studying programming, so I'm asking out of curiosity. Also, EF has migration tools for turning modelling classes into a DB and tools for scaffolding modelling classes from a DB, so how use enums pulled out of DB back in your code is an interesting question (at least for me).
 
I think you are confusing enums which are compile time constants with configuration and environment settings.
 
For example, enum Teams can have Blue team and Red team, and that list is editable.

Yes. And if you had some code that look like:
C#:
var someTeamEnum = new SomeEnum(SomeEnum.v.Red);
Console.WriteLine(someTeamEnum);
and somebody went to the database and renamed the Red team to Fuschia, then your code would be broken until you go and touch the code to change all instances of "Red" to "Fuschia".
 
As an aside, in a few projects I've worked on in the past where we had this kind of thing where we needed to define enums, classes, etc., but the names and values of the types were coming from an external source, I successfully got the team to use the T4 Text Template engine. The text template code would read the source data (ex. Excel Spreadsheet, CSV file, SharePoint list, YAML file, JSON file, database, etc.) and generate the enums and corresponding values.

As example, we'd have a database representing a dungeon with a list of rooms, an graph of the room connections, the contents of the rooms, and monsters within the rooms. The T4 template would query the database, and generate code for each of the rooms as unique partial classes with the contents and connections between the rooms already done. The choice to use a partial class was such that if a developer wanted to add some special case behaviors to some of the rooms, they could do so, otherwise there was default behavior.
 
If considering using T4 templates see one of mine here. Note in the link I've provided guidance on ways to colorize templates as Visual Studio does not natively support T4 template syntax coloring. There is a script included to create the database. Also, although the code uses NET8 the template was written originally in Framework 4.8.

Sample usage for enum with EF Core 8 and SQL-Server:
List<Wine> redWines = context.Wines
    .Where(wine => wine.WineType == WineType.Red)
    .ToList();

foreach (Wine wine in redWines)
{
    Console.WriteLine($"{wine.Name,30}");
}
 

Latest posts

Back
Top Bottom