如果有可能找不到该元素,我应该使用 Single() 还是 SingleOrDefault() ?

发布于 2024-10-31 19:42:06 字数 456 浏览 1 评论 0原文

你最想看到什么?

try
{
  var item = list.Single(x => x.HasFoo);
}
catch(InvalidOperationException e)
{
  throw new InvalidOperationException("Exactly one item with foo expected, none found", e);
}

或者:

var item = list.SingleOrDefault(x => x.HasFoo);
if (item == null)
      throw new InvalidOperationException("Exactly one item with foo expected, none found");

这里的最佳实践是什么?哪一个使异常更容易理解?

What would you prefer to see?

try
{
  var item = list.Single(x => x.HasFoo);
}
catch(InvalidOperationException e)
{
  throw new InvalidOperationException("Exactly one item with foo expected, none found", e);
}

Or:

var item = list.SingleOrDefault(x => x.HasFoo);
if (item == null)
      throw new InvalidOperationException("Exactly one item with foo expected, none found");

What's the best practice here? Which one makes the exception more comprehensible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

巷子口的你 2024-11-07 19:42:06
  • 如果需要 0 或 1 个项目,请使用 SingleOrDefault()
  • 如果需要 1 个项目,而不是 0 或 2 个或更多项目,请使用 Single()

另请记住,有一个可能情况的数量:

  • 当预期 0 或 1 时,您得到 0(好的)
  • 当预期 0 或 1 时,您得到 1(好的)
  • 当预期 0 或 1 时,您得到 2 或更多(错误)

并且:

  • 当 1 时,您得到 0预期为 1(错误),
  • 当预期为 1 时,您得到了 1(好的)
  • 当预期为 1 时,您得到了 2 或更多(错误),

并且不要忘记 First()FirstOrDefault()Any()

  • Use SingleOrDefault() if 0 or 1 items are expected
  • Use Single() if 1, not 0 or 2 and more, item is expected

Also keep in mind that there are a number of possible scenarios:

  • You got 0 when 0 or 1 was expected (ok)
  • You got 1 when 0 or 1 was expected (ok)
  • You got 2 or more when 0 or 1 was expected (error)

And:

  • You got 0 when 1 was expected (error)
  • You got 1 when 1 was expected (ok)
  • You got 2 or more when 1 was expected (error)

And don't forget about First(), FirstOrDefault() and Any()

别把无礼当个性 2024-11-07 19:42:06

我会写:

var item = list.Single(x => x.HasFoo);

如果不返回单个项目的情况如此常见,您需要更友好的错误消息,那么这真的是一个例外吗?

I would write:

var item = list.Single(x => x.HasFoo);

If the case where this does not return a single item is so common you need a friendlier error message, then is it really an exception at all?

满身野味 2024-11-07 19:42:06

我认为这样写是可以的,

var item = list.SingleOrDefault(x => x.HasFoo);
if (item == null) ...

也可以这样写。

if (list.Any(x => x.HasFoo)) ...

但如果您实际上不需要访问该值,

I think it's OK to write

var item = list.SingleOrDefault(x => x.HasFoo);
if (item == null) ...

but you can also write

if (list.Any(x => x.HasFoo)) ...

if you don't actually need access to the value.

我只土不豪 2024-11-07 19:42:06

实际上,它们是相同的。但我更喜欢第二个,因为在前两个中抛出了一个异常异常的代价是昂贵的。

Practically, they are the same. But I prefer second one since one exception is thrown while in the first two. Exceptions are expensive.

潜移默化 2024-11-07 19:42:06

如果您总是期望列表中的一个元素,只需使用

var item = list.Single(x => x.HasFoo);

并在顶级方法中捕获异常,您将在其中记录异常的详细信息并向用户显示友好的消息。

如果您有时期望 0 个或超过 1 个元素,最安全的方法将是

var item = list.FirstOrDefault(x => x.HasFoo);
if (item == null) 
{ 
// empty list processing, not necessary throwing exception
}

我假设的,验证是否存在超过 1 条记录并不重要。

代码项目文章LINQ:Single vs. SingleOrDefault

If you ALWAYS EXPECT  one element in the list, just use 

var item = list.Single(x => x.HasFoo);

and catch exception at the top level method, where you will log details of exception and show friendly message to the user.

If you sometimes expect 0 or more than 1 elements, the safest method will be

var item = list.FirstOrDefault(x => x.HasFoo);
if (item == null) 
{ 
// empty list processing, not necessary throwing exception
}

I assumed, that it is not important to verify, are more than 1 record exist or not.

Similar question was discussed in Code Project article LINQ: Single vs. SingleOrDefault

违心° 2024-11-07 19:42:06

假设您询问的是 0..1 场景,我更喜欢 SingleOrDefault,因为它可以让您指定自己的方式来处理“未找到”场景。

因此,使用一点语法糖的一个好方法是:

// assuming list is List<Bar>();
var item = list.SingleOrDefault(x => x.HasFoo) ?? notFound<Bar>();

其中 notFound() 是:

T notFound<T>()
{
  throw new InvalidOperationException("Exactly one item with foo expected, none found");
}

Assuming you were asking about the 0..1 scenario, I prefer SingleOrDefault because it lets you specify your own way to handle the "nothing found" scenario.

So, a good way to do using a little syntactic sugar, would be:

// assuming list is List<Bar>();
var item = list.SingleOrDefault(x => x.HasFoo) ?? notFound<Bar>();

where notFound() is:

T notFound<T>()
{
  throw new InvalidOperationException("Exactly one item with foo expected, none found");
}
救星 2024-11-07 19:42:06

我宁愿在获取元素之前检查列表中的元素数量,而不是等待异常,然后抛出一个新异常。

var listFiltered = list.Where(x => x.HasFoo).ToList();
int listSize = listFiltered.Count();
if (listSize == 0)
{
    throw new InvalidOperationException("Exactly one item with foo expected, none found");
}
else if (listSize > 1)
{
    throw new InvalidOperationException("Exactly one item with foo expected, more than one found");
}

这些建议很紧凑,但在我看来,更好的是更明确。

(此外,在您的建议中,例外情况并不严格有效:当可能有多个例外时,他们会说“未找到”)

编辑:Jeebus,添加了一行来首先过滤迂腐人士的列表。 (我认为这对任何人来说都是显而易见的)

I'd rather see a check to the number of elements in the list before getting the element, rather than waiting for an exception, then throwing a new one.

var listFiltered = list.Where(x => x.HasFoo).ToList();
int listSize = listFiltered.Count();
if (listSize == 0)
{
    throw new InvalidOperationException("Exactly one item with foo expected, none found");
}
else if (listSize > 1)
{
    throw new InvalidOperationException("Exactly one item with foo expected, more than one found");
}

It's nice that the suggestions are compact, but better to be more explicit IMO.

(Also in your suggestions the exceptions are not strictly valid: they say 'none found' when there could be more than one)

Edit: Jeebus, added one line to filter the list first for pedantic people. (I thought it would have been obvious for anyone)

不知在何时 2024-11-07 19:42:06

我同意 Kieren Johnstone 的观点,不要等待异常,这是相当昂贵的,当然当你多次调用这个方法时。

您的第一个代码片段甚至更昂贵,因为您等待原始异常,而不是给自己抛出一个新异常。

I agree with Kieren Johnstone, don't wait for the exception this is pretty costly, sure when you call this method alot of times.

You're first code snippet is even more expensive, because you wait for the original exception, and than throw yourself a new one.

肩上的翅膀 2024-11-07 19:42:06

单身

如果满足以下条件,它将从元素集合中返回单个特定元素:
找到元素匹配。如果没有或超过一个,则抛出异常
在集合中找到该元素的匹配项。

单一或默认

如果满足以下条件,它将从元素集合中返回单个特定元素:
找到元素匹配。如果有多个匹配项,则会引发异常
在集合中找到该元素。返回默认值,
如果在集合中未找到该元素的匹配项。

这是示例:-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LinqSingleorSingleOrDefault
{
class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string City { get; set; }
}

public class Program
{

    static void Main(string[] args)
    {
        IList<Employee> employeeList = new List<Employee>(){
            new Employee() { Id = 10, Name = "Chris", City = "London" },
            new Employee() { Id=11, Name="Robert", City="London"},
            new Employee() { Id=12, Name="Mahesh", City="India"},
            new Employee() { Id=13, Name="Peter", City="US"},
            new Employee() { Id=14, Name="Chris", City="US"}
        };

        //Single Example

        var result1 = employeeList.Single(); 
        // this will throw an InvalidOperationException exception because more than 1 element in employeeList.

        var result2 = employeeList.Single(e => e.Id == 11);
        //exactly one element exists for Id=11

        var result3 = employeeList.Single(e => e.Name == "Chris");
        // throws an InvalidOperationException exception because of more than 1 element contain for Name=Chris

        IList<int> intList = new List<int> { 2 };
        var result4 = intList.Single(); 
        // return 2 as output because exactly 1 element exists


        //SingleOrDefault Example

        var result5 = employeeList.SingleOrDefault(e => e.Name == "Mohan");
        //return default null because not element found for specific condition.

        var result6 = employeeList.SingleOrDefault(e => e.Name == "Chris");
        // throws an exception that Sequence contains more than one matching element

        var result7 = employeeList.SingleOrDefault(e => e.Id == 12);
        //return only 1 element

        Console.ReadLine();

    }
 }   
}

Single

It returns a single specific element from a collection of elements if
element match found. An exception is thrown, if none or more than one
match found for that element in the collection.

SingleOrDefault

It returns a single specific element from a collection of elements if
element match found. An exception is thrown, if more than one match
found for that element in the collection. A default value is returned,
if no match is found for that element in the collection.

here is sample example:-

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LinqSingleorSingleOrDefault
{
class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string City { get; set; }
}

public class Program
{

    static void Main(string[] args)
    {
        IList<Employee> employeeList = new List<Employee>(){
            new Employee() { Id = 10, Name = "Chris", City = "London" },
            new Employee() { Id=11, Name="Robert", City="London"},
            new Employee() { Id=12, Name="Mahesh", City="India"},
            new Employee() { Id=13, Name="Peter", City="US"},
            new Employee() { Id=14, Name="Chris", City="US"}
        };

        //Single Example

        var result1 = employeeList.Single(); 
        // this will throw an InvalidOperationException exception because more than 1 element in employeeList.

        var result2 = employeeList.Single(e => e.Id == 11);
        //exactly one element exists for Id=11

        var result3 = employeeList.Single(e => e.Name == "Chris");
        // throws an InvalidOperationException exception because of more than 1 element contain for Name=Chris

        IList<int> intList = new List<int> { 2 };
        var result4 = intList.Single(); 
        // return 2 as output because exactly 1 element exists


        //SingleOrDefault Example

        var result5 = employeeList.SingleOrDefault(e => e.Name == "Mohan");
        //return default null because not element found for specific condition.

        var result6 = employeeList.SingleOrDefault(e => e.Name == "Chris");
        // throws an exception that Sequence contains more than one matching element

        var result7 = employeeList.SingleOrDefault(e => e.Id == 12);
        //return only 1 element

        Console.ReadLine();

    }
 }   
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文