Должен ли я использовать Single () или SingleOrDefault (), если есть вероятность, что элемент не будет найден?
30653 просмотра
9 ответа
Что бы вы предпочли увидеть?
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");
Какова лучшая практика здесь? Какой из них делает исключение более понятным?
Автор: the_drow Источник Размещён: 12.11.2019 09:20Ответы (9)
80 плюса
- Используйте,
SingleOrDefault()
если ожидается 0 или 1 - Используйте
Single()
1, а не 0 или 2 и более, ожидается, что элемент
Также имейте в виду, что существует ряд возможных сценариев:
- Вы получили 0, когда ожидали 0 или 1 (хорошо)
- Вы получили 1, когда ожидали 0 или 1 (хорошо)
- Вы получили 2 или более, когда ожидали 0 или 1 (ошибка)
А также:
- Вы получили 0, когда ожидалось 1 (ошибка)
- Вы получили 1, когда 1 ожидалось (хорошо)
- Вы получили 2 или более, когда ожидалось 1 (ошибка)
И не забывайте о том First()
, FirstOrDefault()
иAny()
5 плюса
Я бы написал:
var item = list.Single(x => x.HasFoo);
Если случай, когда это не возвращает ни одного элемента, настолько распространен, вам нужно более дружелюбное сообщение об ошибке, тогда действительно ли это вообще исключение?
Автор: Myster Размещён: 28.08.2011 10:514 плюса
Практически они одинаковы. Но я предпочитаю второе, поскольку в первых двух выбрасывается одно исключение . Исключения дорогие.
Автор: Aliostad Размещён: 11.04.2011 09:363 плюса
Я думаю нормально писать
var item = list.SingleOrDefault(x => x.HasFoo);
if (item == null) ...
но вы также можете написать
if (list.Any(x => x.HasFoo)) ...
если вам на самом деле не нужен доступ к значению.
Автор: Roy Dictus Размещён: 11.04.2011 09:382 плюса
Если вы ВСЕГДА ОЖИДАЕТЕ один элемент в списке, просто используйте
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 записи или нет.
Подобный вопрос обсуждался в статье Code Project LINQ: Single против SingleOrDefault.
Автор: Michael Freidgeim Размещён: 06.06.2013 11:441 плюс
Я предпочел бы увидеть проверку количества элементов в списке перед тем, как получить элемент, вместо того, чтобы ждать исключения, а затем выдавать новый.
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, добавил одну строку, чтобы сначала отфильтровать список для педантичных людей. (Я думал, что это было бы очевидно для всех)
Автор: Kieren Johnstone Размещён: 11.04.2011 09:291 плюс
Предполагая, что вы спрашивали о сценарии 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");
}
Автор: Juanjo
Размещён: 11.10.2013 06:06
0 плюса
Я согласен с Киреном Джонстоном, не ждите исключения, это довольно дорого, конечно, когда вы вызываете этот метод много раз.
Ваш первый фрагмент кода еще дороже, потому что вы ждете исходное исключение, а потом бросаете себе новое.
Автор: ChristiaanV Размещён: 11.04.2011 09:370 плюса
Один
Он возвращает один конкретный элемент из коллекции элементов, если найдено соответствие элемента. Исключение выдается, если для этого элемента в коллекции не найдено ни одного, ни нескольких совпадений.
SingleOrDefault
Он возвращает один конкретный элемент из коллекции элементов, если найдено соответствие элемента. Исключение выдается, если для этого элемента в коллекции найдено более одного совпадения. Возвращается значение по умолчанию, если для этого элемента в коллекции не найдено совпадений.
Вот пример примера:
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();
}
}
}
Автор: Nimesh khatri
Размещён: 09.03.2017 10:40
Вопросы из категории :
- c# Преобразовать десятичную в двойную?
- c# Как рассчитать чей-то возраст в C #?
- c# Как вы сортируете словарь по значению?
- c# В чем разница между int и Integer в Java и C #?
- c# Как создать новый экземпляр объекта из Типа
- .net Действительно ли опечатанные классы действительно предлагают преимущества?
- .net Setting Objects to Null/Nothing after use in .NET
- linq LINQ-запрос к DataTable
- linq Условные запросы Linq
- linq Конфликт данных в LINQ
- linq Есть ли способ переопределить пустой конструктор в классе, сгенерированном LINQtoSQL?
- linq Отладка LINQ to SQL SubmitChanges ()
- coding-style Когда вы используете ключевое слово "это"?
- coding-style Синтаксические стили C ++
- coding-style Должна ли функция иметь только один оператор возврата?
- coding-style Сколько аргументов конструктора слишком много?
- coding-style Одинарные кавычки против двойных кавычек в Python