如何将数字动态绑定到枚举
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 将枚举数据绑定到组合框? [复制]