Trouble with an enumeration as a key in a Dictionary collection
我有一个场景,在这个场景中,我使用字典保存某个系统接受的事务类型列表。字典中的键是枚举字段,值是int。
在系统中的某个时刻,我们将要做如下的事情:
1 | sqlCommand.Parameters.AddWithValue("@param", LookupDictionary[argument.enumField]); |
当我们在字典中查找字段时,我们将得到正确的整数值,以供数据库使用。我已经考虑过实际使用枚举int值,但这并不完全正确。我们正在与一个系统进行交互,在这个系统中,我们需要输入一个幻数来表示我们正在进行的更新。
上面的代码工作得很好。我有一个初始值设定项方法,用于添加已知类型:
1 2 3 4 | LookupDictionary = new Dictionary<mynamespace.myproject.myclass.enumType, int>(); LookupDictionary.Add(enumType.entry1, 4); LookupDictionary.Add(enumType.entry2, 5); LookupDictionary.Add(enumType.entry3, 6); |
此代码也可以正常工作。
但在上面,在我真正开始使用lookupDictionary之前,我验证了正在发出的请求实际上被设置为我们支持的枚举值。这是lookupDictionary的主要原因,它保存了有效的枚举项(这个方法不使用有效的枚举项)。
这是不起作用的代码:系统无法识别枚举是否匹配。在调试器中,我可以看到lookupDictionary中的条目列表确实显示了它具有entry2的值——它只是这样调用它,entry2。另一方面,传入的EnumField具有完整的命名空间;myNamespace.myProject.myClass.EnumType.Entry2—我想这就是为什么它不将它们视为相同的原因。
1 2 3 4 | if (!LookupDictionary.ContainsKey(argument.enumField)) { throw new InvalidOperationException("argument.enumField not valid in blahMethod."); } |
我有没有提到这是通过WCF服务传递的?但我没有使用自动生成的代理…导线两侧的两个项目都共享类型作为项目引用,我在代码中构建了通道客户机。
有什么想法吗?我做错了吗?以枚举作为键的字典工作不好吗?是WCF的事吗?
注意:感谢您提供有关设置枚举以包含magic int的建议。但是,我希望将这些设置为配置,因为"magic numbers"4 5和6可能会在将来发生变化。因此,如果我按照建议将它们编码到枚举中:
1 2 3 4 5 6 | public enum MyEnum { MyValue1 = 4, MyValue2 = 5, MyValue3 = 6 } |
我无法在将来的运行时编写一个设置幻数的方法;相反,它需要更改代码。
不要使用枚举作为键,而是使用枚举的整数表示形式。
例如:
1 2 3 4 | LookupDictionary = new Dictionary<int, int>(); LookupDictionary.Add((int)enumType.entry1, 4); LookupDictionary.Add((int)enumType.entry2, 5); LookupDictionary.Add((int)enumType.entry3, 6); |
这样,您就可以使用字典中相同的"containskey"方法。我不确定这是否比
您根本不需要查找表:
1 2 3 4 5 6 7 8 9 10 11 12 13 | public enum MyEnum { MyValue1 = 4, MyValue2 = 5, MyValue3 = 6 } // Sample usage MyEnum firstEnum = MyEnum.MyValue1; int intVal = (int)firstEnum; // results in 4 // Enum Validation bool valid = Enum.IsDefined(typeof(MyEnum), intVal); // results in true |
可以使用语法显式设置枚举的值
1 2 3 4 5 | enum ArgumentTypes { Arg1 = 1; Arg2 = 3; Arg3 = 5; } |
您不需要在枚举中保持每个值的顺序,这样语法就可以工作了。
要验证是否只使用对该方法有效的参数,请尝试此示例代码。注意,我建议在此上下文中对InvalidOperationException使用ArgumentException。
1 2 3 4 5 6 7 8 | public void DoDbWork(ArgumentTypes argType, object otherParameter) { if (argType == ArgumentTypes.Arg3) { throw new ArgumentException("Argument of value" + argType +" is not valid in this context","argType"); } // Handle db transaction here } |
要添加int值作为参数:
1 | cmd.Parameters.AddWithValue("@paramName", (int)argType); |
是否可以考虑将枚举显式键入int(或任何基础类型),然后将每个枚举的值设置为数据库值?您已经将枚举与数据库紧密耦合,因此关系将由C(当前硬编码)或SQL(可能是返回ID的过程,以及可以解析为枚举的字符串)来指示。
假设您的枚举是一个int…
1 2 3 4 5 | enum enumType { entry1 = 4, entry2 = 5, entry3 = 6 } |
添加参数时,您只需将其转换为枚举的基础类型。
1 | sqlCommand.Parameters.AddWithValue("@param", (int)argument.enumField); |