代码之家  ›  专栏  ›  技术社区  ›  mjb

如何将数字动态绑定到枚举

  •  2
  • mjb  · 技术社区  · 8 年前

    下面是我们如何定义要枚举的数字:

    enum Color
    {
        Red = 1,
        Green = 2,
        Blue = 3
    }
    

    由此,数值为常量。

    我想在运行时动态分配它怎么样?或者在代码中更改它?然后变为这样:

    enum Color
    {
        Red = 4,
        Green = 8,
        Blue = 9
    }
    

    我有一种方法

    Enum.BindNumber(Color.Red, 4);
    

    解决方案:

    阅读了下面的答案/信息后,我编写了一个自定义类来解决此问题:

    public enum SectionName
    {
        UnknownSection,
        SectionA,
        SectionB,
        SectionC,
        SectionD
    }
    
    public class Section
    {
        Dictionary<SectionName, int> dic = new Dictionary<SectionName, int>();
    
        public int SectionA { get { return dic[SectionName.SectionA]; } }
        public int SectionB { get { return dic[SectionName.SectionB]; } }
        public int SectionC { get { return dic[SectionName.SectionC]; } }
        public int SectionD { get { return dic[SectionName.SectionD]; } }
    
        public int this[SectionName sn]
        {
            get
            {
                if (dic.ContainsKey(sn))
                    return dic[sn];
                return 0;
            }
            set
            {
                dic[sn] = value;
            }
        }
    
        public SectionName this[int num]
        {
            get
            {
                foreach(var kv in dic)
                {
                    if (kv.Value == num)
                        return kv.Key;
                }
                return SecionName.UnknownSection;
            }
            set
            {
                dic[value] = num;
            }
        }
    }
    

    更新:背后的场景

    我想回答下面的一些反馈和问题,为什么我需要做这个枚举>&燃气轮机;数字绑定?我将在下面解释我的场景:

    你们知道,从长远来看,改变数据库结构对我来说有点头疼。我觉得更改代码要比更改数据库结构容易得多。

    如果更改数据库结构,将对编码部分的整体产生地震破坏等效效果。但您始终可以在不更改数据库的情况下更改代码。

    因此,从长远来看,数据库必须以it的形式进行良好的设计,使其能够灵活地适应变化并可持续地进行程序版本演化。

    在我当前的新项目中。。这是定制的web cms项目。这是我第一次尝试,我只用了一张表就建立了这个网站。以下是表格结构:

    CREATE TABLE `item` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `parent_id` int(10) unsigned DEFAULT NULL,
      `key` varchar(100) DEFAULT NULL,
      `data` mediumtext,
      `seq` int(10) unsigned DEFAULT NULL,
      `status` int(10) unsigned DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    

    表结构

    ------------------------------------
    Columns   | Data Type              |
    ------------------------------------
    id        | int (auto-increment)   |
    parent_id | int                    |
    key       | varchar                |
    data      | mediumtext             |
    seq       | int                    |
    status    | int                    |
    ------------------------------------
    

    数据库中的第一个项是域项,如下所示:

    第1项

    id = 1 <auto-generate> first item
    parent_id = 0 (this is the first item, definitely no parent
    key = 'mydomainname.com'
    data = null (not important at this stage)
    seq = null (not important at this stage)
    status = null (not important at this stage)
    

    网站中有许多预定义的部分,例如:

    • 首页滑块
    • Web编辑器(用户)
    • 页脚块
    • 类别1
    • 类别2

    这些部分中的每一部分都将在 枚举

    Section            | Enum
    -------------------------------------
    Front Page Slider  | FrontPageSlider
    Web Editors (user) | UserList
    Footer Blocks      | FooterBlock
    Category1          | Category1
    Category2          | Category2
    

    我使用“key”存储所有信息<&燃气轮机;“data”(父级<>子级)匹配方法,并将其存储在数据库中。

    例如:存储滑块数据

    首先,创建滑块父项

    id = 2 <auto-generate> 2nd item
    parent_id = 1 (refers to 1st item)
    key = 'FrontPageSlider'
    data = null (not important at this stage)
    seq = null (not important at this stage)
    status = null (not important at this stage)
    

    现在,是幻灯片数据

    第1张幻灯片

    id = 3 <auto-generate> 3rd item
    parent_id = 2 (refers to 2nd item)
    key = 'my_first_photo.jpg'
    data = null (not important at this stage)
    seq = 1 
    status = 1
    

    第二张幻灯片

    id = 4 <auto-generate>
    parent_id = 2 (refers to 2nd item)
    key = 'dog_cat_running.jpg'
    data = null (not important at this stage)
    seq = 1 
    status = 1
    

    另一个示例:存储用户编辑器的数据

    创建用户父项

    id = 5 <auto-generate>
    parent_id = 1 
    key = 'UserList'
    data = null (not important at this stage)
    seq = null (not important at this stage)
    status = null (not important at this stage)
    

    第一个用户:

    id = 6 <auto-generate>
    parent_id = 5
    key = 'adam'
    data = 'pwd=fa23f....2f283|salt=faff...awefw|fullname=Adam Smith
    seq = null (not important at this stage)
    status = 1
    

    第二用户:

    id = 7 <auto-generate>
    parent_id = 5
    key = 'jasmine'
    data = 'pwd=0x0a2f....2f3|salt=0xfxff...afb|fullname=Jasmine Irene
    seq = null (not important at this stage)
    status = 1
    

    好了,现在您了解了数据是如何相互链接的。

    固定部分将在编码中定义为Enum,但id在数据库中自动生成为第二级父级。我需要将数据库中的数字(自动递增的id)绑定到枚举,以便我可以从数据库中获取父项,然后再获取子项。

    正如你们中的一些人所说,这是一次疯狂的尝试。是的,我完全同意你们这么疯狂。我不知道你对此有何感想,但我个人认为,这是一个非常棒的尝试,可以将一张桌子用于所有内容:)

    4 回复  |  直到 8 年前
        1
  •  2
  •   Sweeper    8 年前

    不,但作为一种解决方法,您可以考虑 Dictionary :

    var colorsDict = new Dictionary<Color, int>() {
       {Color.Red, 4}, {Color.Green, 8}, {Color.Blue, 9}
    };
    

    您可以随时动态更改它。

    然而,很明显,您不能将数字强制转换为枚举并期望得到正确的结果:

    (Color)8 // probably not green
    

    即使语言确实支持上述内容,但如果值可以更改,那么这样做仍然会有问题。您可能会意外更改某些内容,而所有内容都会中断。

        2
  •  1
  •   Martin Zikmund    8 年前

    不,这是不可能的,您可以将枚举值视为常量,将名称视为“占位符”,以使代码更具可读性。在幕后,枚举只是一个结构,它具有 value__ 字段(数值)和命名值的几个常量。因为它们是常量,所以不能在运行时修改它们。

    .class private auto ansi sealed Color extends [mscorlib]System.Enum
    {
      .field public specialname rtspecialname int32 value__
      .field public static literal valuetype Color Red = int32(0x00000001)
      .field public static literal valuetype Color Green = int32(0x00000002)
      .field public static literal valuetype Color Blue= int32(0x00000003)
    }
    
        3
  •  1
  •   akop    8 年前

    我把你的包装纸改了。

        /// <summary>
        /// This class wrapps any enum and make values changeable.
        /// </summary>
        /// <typeparam name="T">Struct to be wrapped</typeparam>
        public class ChangeableEnum<T> where T : struct, IConvertible
        {
            // This dict contains all values of enum
            IDictionary<T, int> _dict;
    
            /// <summary>
            /// Constructor intializes with the given enum (as generic-class-type)
            /// </summary>
            public ChangeableEnum()
            {
                _dict = new Dictionary<T, int>();
    
                // iterate over each value and get value
                foreach (T obj in Enum.GetValues(typeof(T)))
                    _dict.Add(obj, Convert.ToInt32(obj));
            }
    
            /// <summary>
            /// Get or set a value of enum.
            /// </summary>
            /// <param name="obj">Enum-type to get or set</param>
            /// <returns>Value of given enum-type.</returns>
            public int this[T obj]
            {
                get { return _dict[obj]; }
                set { _dict[obj] = value; }
            }
        }
    

    此代码未经测试,可能存在一些错误。

    如何用于颜色枚举:

        public enum Color
        {
            Red = 4,
            Green = 8
        }
    

    在一种方法中

    ChangeableEnum<Color> test = new ChangeableEnum<Color>();
    
    // get
    System.Diagnostics.Trace.WriteLine(test[Color.Red]);
    
    // set
    test[Color.Red] = 5436;
    
    // get again
    System.Diagnostics.Trace.WriteLine(test[Color.Red]);
    

    但我认为,您在错误的上下文中使用枚举。

        4
  •  1
  •   James Law    8 年前

    这简直是疯了。但我喜欢偶尔有点疯狂。。。

    public struct Colour
    {
        private static Dictionary<string, int> _bindings = new Dictionary<string, int>();
        private string _key { get; set; }
    
        public static Colour Red => new Colour(nameof(Red));
        public static Colour Green => new Colour(nameof(Green));
        public static Colour Blue => new Colour(nameof(Blue));
    
        private Colour(string colour)
        {
            _key = colour;
        }
    
        public static void BindNumber(Colour colour, int value)
        {
            _bindings[colour._key] = value;
        }
    
        public static explicit operator int (Colour colour)
        {
            return _bindings.TryGetValue(colour._key, out var value) ? value : throw new ArgumentOutOfRangeException(nameof(colour));
        }
    
        public static implicit operator string (Colour colour)
        {
            return colour.ToString();
        }
    
        public static bool operator ==(Colour colour1, Colour colour2)
        {
            return colour1._key == colour2._key;
        }
    
        public static bool operator !=(Colour colour1, Colour colour2)
        {
            return colour1._key != colour2._key;
        }
    
        public static bool operator ==(Colour colour, int value)
        {
            return (int)colour == value;
        }
    
        public static bool operator !=(Colour colour, int value)
        {
            return (int)colour != value;
        }
    
        public override bool Equals(object obj)
        {
            return ((Colour)obj)._key == _key;
        }
    
        public override int GetHashCode()
        {
            return _key.GetHashCode();
        }
    
        public override string ToString()
        {
            return _key;
        }
    }
    

    要使用这个疯狂的类:

    Colour.BindNumber(Colour.Red, 3);
    Colour.BindNumber(Colour.Blue, 6);
    Colour.BindNumber(Colour.Green, 7);
    
    var redTest = Colour.Red;
    var greenTest = Colour.Green;
    var blueTest = Colour.Blue;
    
    Console.WriteLine(redTest); //Red
    Console.WriteLine((int)redTest); //3
    
    Console.WriteLine(greenTest); //Green
    Console.WriteLine((int)greenTest); //7
    
    Console.WriteLine(blueTest); //Blue
    Console.WriteLine((int)blueTest); //6
    
    var red1 = Colour.Red;
    var red2 = Colour.Red;
    var green1 = Colour.Green;
    
    Console.WriteLine(red1 == red2); //True
    Console.WriteLine(Colour.Red == Colour.Red); //True
    Console.WriteLine(red1 == green1); //False
    Console.WriteLine(red1 == 3); //True
    Console.WriteLine(red1 == 5); //False
    

    注意事项:

    • 这整个想法有点愚蠢。我不建议你使用它。
    • 这段代码绝对不是线程安全的!
    • 除了解决你眼前的问题之外,我还没有考虑过后果。也许你应该?

    享受