实际使用.Single(),。SingleOrDefault()方法

时间:2016-09-07 09:48:59

标签: c#

我经常在我们的项目中遇到非信息性消息,例如"序列包含多个元素"。它不时发生。

最好不要检查:

var count = collection.Count(i => predicate);
if (count > 1)
{
   throw new InformativeException("...");
}

if (count == 0)
{
    throw new AnotherInformativeException("...");
}

我真的不明白在什么情况下Single()/ SingleOrDefault()可能有用。只有当你捕获InvalidOperationException并尝试将其转换为更具信息量的时候。

4 个答案:

答案 0 :(得分:2)

您是对的,错误消息是通用的,不是非常具体。但是,我认为他们不需要:

有两种情况:

  1. 合理地可能存在<> 1个元素(例如,由于配置文件条目无效或用户输入错误)。在这种情况下,检查列表中的项目数量并抛出信息性异常是正确的做法。

  2. <> 1个元素是不可能的 - 也就是说,如果你在这里得到<> 1个元素,那么你在其他地方就会出现编程错误。例如:

    // getItem's documentation guarantees that each element has a unique ID and
    // that there is an element with ID 1.
    var myItems = getItems();
    
    // if this fails, there is an implementation error in getItems
    var item1 = myItems.Single(x => x.ID == 1);
    

    在这种情况下,默认错误消息通常就足够了。在这里使用Single基本上充当运行时断言。

答案 1 :(得分:1)

Single和SingleOrDefault()可用于以下场景:

  • Single()期望在您正在使用的匹配序列中找到单个元素。 如果序列为空或包含多个元素,它会抛出一个预期。

  • SingleOrDefault()在匹配序列为空(并返回详细信息,通常为null)时不会抛出异常,但在匹配序列包含多个元素时会抛出异常。

您还可以使用以下LINQ函数:

  • Count()检查更大的值(例如&gt; 1)

  • 返回true的
  • Any()是mathicng序列包含一个或多个项目。

答案 2 :(得分:0)

当你期望一个,只有一个,或者一个或没有(分别)时,应该使用

SingleSingleOrDefault

你可以通过明确地检查计数(这是传统的方法)来做你建议的方式,但是当你让LINQ为你抛出异常时,代码可以更简洁和/或更容易理解:

try {

    // a bunch of stuff

    var x = y.Where(z => z.ID = id).Single();

    // more stuff

} catch (SomeException e) {
    // other expected issue 
} catch (OtherException e) {
    // other expected issue 
} catch (InvalidOperationException e) {
    // how'd we wind up with more (or less) than 1???
} catch (Exception e) {
    // unexpected issue
}

有些人(包括我自己)可能更喜欢将主要逻辑块的外围验证代码(基本上就是上面所代表的代码)放在一边。请注意,这并没有忽略主要逻辑要求,因为Single()明确地告诉我们,我们期望只有一个项目,因此通过将计数验证移动到异常处理程序不会丢失知识。

我确实希望它抛出一个比InvalidOperationException更具体的例外但是......这非常通用。

答案 3 :(得分:0)

如果我希望正好一个元素,我会使用以下模式:

try {
    var singleElement = x.SingleOrDefault(x => /* some expression */);
}
catch (InvalidOperationException iopex) {
   throw new InformativeException("More than one element found.");
}
if (singleElement == null) {
   throw new InformativeException("No element found.");
}
// work with singleElement from here