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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何将数字动态绑定到枚举相关的知识,希望对你有一定的参考价值。

这是我们如何定义枚举数:

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;
        }
    }
}

更新:背后的情景

我想回答下面的一些反馈和问题我被问到为什么我需要这样做Enum >>数字绑定?我将在下面解释我的情景:

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

如果改变数据库结构,它将对编码部分的整体具有相同的地震破坏效果。但您可以随时更改代码而无需更改数据库。

因此,从长远来看,数据库必须以其形式精心设计,使其具有灵活性和适应变化的能力,并可持续用于程序版本的演变。

在我目前的新项目中..它是自定义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                    |
------------------------------------

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

第一项

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)

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

  • 首页滑块
  • 网络编辑(用户)
  • 页脚块
  • 组别
  • 第2类
  • 等等....

这些部分中的每一部分都将在Enum中定义

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

我使用“key”<>“data”(parent <> child)匹配方法存储所有信息并将其存储在数据库中。

例如:存储滑块数据

首先,创建Slider Parent Item

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)

现在,是幻灯片数据

第一张幻灯片

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)从数据库绑定到Enum,这样我就可以从数据库中获取父项,然后再获取子项。

正如你们有些人所说,这是疯狂的尝试。是的,我完全赞同你这些疯狂的人。我不确定你对它的感受,但我个人觉得这只是一个非常棒的尝试只使用一张桌子:)

答案

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

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

您可以随时动态更改它。

但是,您显然无法将数字转换为枚举并期望得到正确的结果:

(Color)8 // probably not green

即使语言确实支持上述内容,当值发生变化时,这样做仍然会有问题。你可能会意外地改变一切,一切都会中断。

另一答案

不,这是不可能的,您可以将枚举值视为常量,将名称视为“占位符”,以使代码更具可读性。在幕后,枚举只是一个结构,它有一个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)
}
另一答案

我重写你的包装。

    /// <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; }
        }
    }

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

如何使用color-enum:

    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]);

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

另一答案

这都是疯狂的。但我偶尔会有点疯狂......

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

注意事项:

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

请享用!

以上是关于如何将数字动态绑定到枚举的主要内容,如果未能解决你的问题,请参考以下文章

WPF 数据绑定:如何使用 XAML 将枚举数据绑定到组合框? [复制]

如何将 View 类中的代码片段移动到 OnAppearing() 方法?

实用代码片段将json数据绑定到html元素 (转)

如何组合绑定片段而不将它们包装在 XML 文字中

如何将值绑定到类属性?

如何将片段目标绑定到底部导航栏中的菜单项?