【问题标题】:SingleOrDefault() Throw exception Sequence contains more than one matching elementSingleOrDefault() 抛出异常序列包含多个匹配元素
【发布时间】:2014-07-24 20:49:41
【问题描述】:

我有字典,几乎没有像这样存储的元素

    Dictionary<string, string> dService = new Dictionary<string, string>();
    dService.Add("UPS Express Plus", "001");
    dService.Add("UPS Express Plus", "054");
    dService.Add("UPS Express", "007");
    dService.Add("UPS Express Saver", "065");
    dService.Add("UPS Expedited", "008");
    dService.Add("UPS Express Plus", "001");

这样我试图根据值获取密钥

dService.SingleOrDefault(x => x.Value == ("001")).Key

此代码抛出错误。我搜索谷歌并得到解决方案,人们说不要使用SingleOrDefault() 而不是使用FirstOrDefault()

但我没有很好的解释为什么&当SingleOrDefault()抛出错误?我应该假设字典存储多个值这就是SingleOrDefault() 不起作用的原因吗?

寻找解释何时为什么和何时SingleOrDefault() 抛出错误....请指导我示例情况。谢谢

【问题讨论】:

  • 这不会抛出异常。
  • "why & when SingleOrDefault() throw error" - 根据documentation: [SingleOrDefault] 返回序列的唯一元素,如果序列为空则返回默认值; 如果序列中有多个元素,此方法将引发异常。
  • 此代码抛出错误。什么错误?这对我来说没有任何异常。可能例外在其他地方..
  • 您没有提供Minimal, Complete, and Verifiable example。我敢打赌,您的真实字典至少包含两个 KeyValuePair,其值为 "001"

标签: c# linq dictionary


【解决方案1】:

首先,您上面的示例数据不会抛出,因为它不包含多个相等的值 "001"。如果您使用Value="001" 添加两个值,则可以。

如果你枚举一个字典,你会得到一个IEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt;。您在字典中要求 第一个也是唯一的值,即"001"。当然,字典可以包含多个相等的(但只有唯一的键)。

所以你可以使用FirstOrDefault 代替,它不会引发多个结果。另一种方法是使用Where 查找所有内容,然后使用Select 键:

IEnumerable<string> all001ValKeys = dService
    .Where(kv => kv.Value == "001")
    .Select(kv => kv.Key);

SingleOrdefault(或Single)很方便,如果您想确保如下业务规则:

var record = someTable.Single(obj => obj.ID == 123); // ID must be unique

这使您的代码更具可读性,并且还遵循“快速失败”规则。

【讨论】:

  • 此外,Single 将测试列表中包含的每个对象,而 First 将在第一个匹配元素处停止。
  • @gretro:它不会测试每个对象,它只会检查是否有另一个。这是一个区别,因为性能不应该是避免Single/SingleOrDefault 的标准。选择最适合您的业务规则的内容。
【解决方案2】:

如果你想要 list 中的第一个元素,则使用 FirstOrDefault ,如果 list 中没有数据,它将返回默认值(即为 null),否则将返回 list 的第一个元素。

当你确定 list 中只有一个元素时使用 SingleOrDefault ,如果它不在 list 中,它将返回默认值(即为 null),但如果它有超过单个值,它会抛出你 exectption。

我希望这个解释对你有用。

【讨论】:

    【解决方案3】:

    请注意,Dictionary 上的 FirstOrDefault 返回一个 KeyValuePair,其中包含定义的 Key 和 Value 类型的默认值。由于您使用字符串作为键和值,因此两者都将为空。因此,您的 LINQ 表达式的结果将为 null,并且使用该键可能会导致稍后在您的代码中出现 NullReferenceException。

    【讨论】:

    • 你错了。自己去试试吧,它会返回一个 KeyValuePair 包含指定类型的默认值。
    • 你的例子总是返回一个结果而不是默认值,因为没有谓词。但是new Dictionary&lt;string, string&gt; { { "A", "001" } }.FirstOrDefault(x =&gt; x.Value == "002"); 返回一个 KeyValuePair,它本身不为空,但包含两个空值。
    • 现在我明白你的意思了,KeyValuePair&lt;Tk, Tv&gt; 是一个结构而不是一个类。 struct 是一种值类型,并且始终具有(默认)值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多