关于c#:将枚举作为Dictionary集合中的键的问题

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"方法。我不确定这是否比List好得多。


您根本不需要查找表:

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