【问题标题】:Trouble with an enumeration as a key in a Dictionary collection枚举作为字典集合中的键的问题
【发布时间】:2010-03-05 00:48:55
【问题描述】:

我有一个场景,我使用字典来保存某个系统接受的交易类型列表。 Dictionary 中的 key 是 enum 字段,value 是 int。

在系统中的某个时刻,我们会想要做这样的事情:

sqlCommand.Parameters.AddWithValue("@param", LookupDictionary[argument.enumField]);

当我们在字典中查找该字段时,我们将获得正确的整数值以提供给数据库。我曾考虑过为此实际使用 enum int 值,但这并不完全正确。我们正在与一个系统交互,我们需要输入一个幻数来表示我们正在执行的更新类型。

上面的代码运行良好。我有一个添加已知类型的初始化方法:

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 - 我想这就是为什么它不认为它们是相同的。

if (!LookupDictionary.ContainsKey(argument.enumField))
{
    throw new InvalidOperationException("argument.enumField not valid in blahMethod.");
}

我是否提到这是通过 WCF 服务传递的?但是我没有使用自动生成的代理......线路两侧的两个项目都共享类型作为项目引用,并且我在代码中构建了我的频道客户端。

有什么想法吗?我做错了吗?以枚举为键的字典不能很好地工作吗?这是 WCF 的事情吗?

注意:感谢有关设置枚举以包含魔法 int 的建议。但是,我想将它们设置为配置,因为“幻数” 4 5 和 6 可能会在未来发生变化。因此,如果我按照建议将它们编码到枚举中:

public enum MyEnum
{
    MyValue1 = 4,
    MyValue2 = 5,
    MyValue3 = 6
}

我失去了编写在运行时设置未来幻数的方法的能力;相反,它需要更改代码。

【问题讨论】:

  • 字典没有枚举类型作为键的问题,我怀疑它与WCF有关。这里只有很小的 sn-ps 代码 - 一个简短但完整的重现问题的程序可能会导致一些答案。从最简单的情况开始 - 将枚举键添加到字典中,并验证它是否存在。然后逐步构建它,直到找到代码失败的地方。
  • 我相信你是对的。我有一种强烈的感觉,我只是在某个地方出现了一些小错误;只是想我会把它扔在那里。至少我认识的一个 WCF 人员认为它可能是自动生成的代理,这就是为什么我根据我的 DataContracts 的共享项目重新组织。一切都很顺利,但并没有解决问题。

标签: c# wcf dictionary enums


【解决方案1】:

不要使用枚举作为键,而是使用枚举的整数表示。

例如:

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&lt;int&gt; 的性能好得多

【讨论】:

  • 嗯,谢谢...我喜欢这个...打算试试。应该给我想要的相同的可维护性,并保留以后从配置中重写它的能力。
  • 成功了!仍然不确定发生了什么......还有其他字段正在传递给该服务,这些字段没有正确“通过”,所以我怀疑其他地方存在问题;但这解决了我的问题。谢谢!
【解决方案2】:

这里根本不需要查找表:

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

【讨论】:

  • 枚举中有此方法无法处理的条目。因此,查找的重点是检查我们是否被调用,请求设置为我们无法处理的类型之一。
【解决方案3】:

您是否可以考虑将枚举显式键入为 int(或任何基础类型),然后将每个枚举的值设置为数据库值?您已经将枚举与数据库紧密耦合,因此关系将由 C#(当前的硬编码)或 SQL(可能是返回 ID 的 proc 以及可以解析为枚举的字符串)指定.)

假设您的枚举是一个整数...

enum enumType {
    entry1 = 4,
    entry2 = 5,
    entry3 = 6
}

添加参数时,您只需将其转换为枚举的基础类型。

sqlCommand.Parameters.AddWithValue("@param", (int)argument.enumField);

【讨论】:

  • 枚举存在以表示数据库中的有效值,紧密耦合不是问题。问题是我希望能够在运行时生成正确的“幻数”,以防它们发生变化。如果我按照您的指示设置它们,entry1 = 4,我无法围绕它进行循环。实际值不会改变,只是它们的 int 表示可能会改变。例如,entry1 今天可能是 4,但一周内可能是 40。 Lookup.Add 允许我稍后编写一个方法,该方法将进入并从数据库中提取正确的魔法值并将它们存储在查找字典中。
【解决方案4】:

您可以使用语法显式设置枚举的值

enum ArgumentTypes {
    Arg1 = 1;
    Arg2 = 3;
    Arg3 = 5;
}

您无需在枚举中保持每个值的顺序即可使此语法正常工作。

要验证是否只使用了对该方法有效的参数,请尝试此示例代码。注意我建议在这种情况下使用 ArgumentException 而不是 InvalidOperationException。

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值作为参数:

cmd.Parameters.AddWithValue("@paramName", (int)argType);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-29
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 2018-10-30
    • 2011-08-10
    • 1970-01-01
    • 2018-01-09
    相关资源
    最近更新 更多