Пустой ILookup<K, T>
У меня есть метод, который возвращает ILookup
, В некоторых случаях я хочу вернуть пустую ILookup
как ранний выход. Каков наилучший способ построения пустого ILookup
?
6 ответов
В дополнение к ответам от mquander и Vasile Bujac, вы можете создать приятный, простой синглтон-эск EmptyLookup<K,E>
Класс следующим образом. (По моему мнению, создание полноценного ILookup<K,E>
реализация согласно ответу Василе.)
var empty = EmptyLookup<int, string>.Instance;
// ...
public static class EmptyLookup<TKey, TElement>
{
private static readonly ILookup<TKey, TElement> _instance
= Enumerable.Empty<TElement>().ToLookup(x => default(TKey));
public static ILookup<TKey, TElement> Instance
{
get { return _instance; }
}
}
Там нет встроенного, поэтому я бы просто написал метод расширения, который выполняет что-то вроде new T[0].ToLookup<K, T>(x => default(K));
Я сильно сомневаюсь, что возвращение нуля было бы более правильным здесь. Практически никогда не требуется возвращать значение null из метода, который возвращает коллекцию (в отличие от пустой коллекции). Я не могу больше не согласиться с людьми, которые предлагают это.
Вы можете создать одноэлементный класс для пустых поисков.
public sealed class EmptyLookup<T, K> : ILookup<T, K>
{
private static readonly EmptyLookup<T, K> _instance
= new EmptyLookup<T, K>();
public static EmptyLookup<T, K> Instance
{
get { return _instance; }
}
private EmptyLookup() { }
public bool Contains(T key)
{
return false;
}
public int Count
{
get { return 0; }
}
public IEnumerable<K> this[T key]
{
get { return Enumerable.Empty<K>(); }
}
public IEnumerator<IGrouping<T, K>> GetEnumerator()
{
yield break;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
yield break;
}
}
тогда вы можете написать код так:
var x = EmptyLookup<int, int>.Instance;
Преимущество создания нового класса заключается в том, что вы можете использовать оператор "is" и проверять равенство типов:
if (x is EmptyLookup<,>) {
// ....
}
На основании ответа LukeH я бы создал статический класс Lookup
с Empty<TKey, TElement>
метод. Таким образом, вы можете использовать так же, как Enumerable.Empty<T>
,
public static class Lookup
{
public static ILookup<TKey, TElement> Empty<TKey, TElement>()
=> Enumerable.Empty<TElement>().ToLookup(x => default(TKey));
}
Пример использования: Lookup.Empty<string, string>()
Создайте пустой список, затем выполните ToLookup() для него, например так:
List<Point> items = new List<Point>();
ILookup<int, int> lookup = items.ToLookup(p => p.X, p => p.Y);
Удачи!
Спасибо @mqp за хорошую идею. Я могу предложить несколько методов расширения на основе этого подхода:
public static class IEnumerableExtensions
{
public static ILookup<TKey, TElement> ToEmptyLookup<TKey, TElement>(this IEnumerable<TElement> elements) => new TElement[0].ToLookup(k => default(TKey));
public static ILookup<TKey, TElement> ToEmptyLookup<TKey, TElement>(this IDictionary<TKey, TElement> elements) => new TElement[0].ToLookup(k => default(TKey));
public static ILookup<TKey, TElement> ToEmptyLookup<TKey, TElement>(this IGrouping<TKey, TElement> elements) => new TElement[0].ToLookup(k => default(TKey));
public static ILookup<TKey, TElement> ToEmptyLookup<TKey, TElement>(this IEnumerable<ILookup<TKey, TElement>> elements) => new TElement[0].ToLookup(k => default(TKey));
}
Или что-то еще в духе LINQ:
public static class Utility
{
public static ILookup<TKey, TElement> EmptyLookup<TKey, TElement>(Func<TKey, TKey> keySelector,
Func<TKey, TElement> elementSelector)
{
return Enumerable.Empty<TKey>().ToLookup(keySelector, elementSelector);
}
}
Вы можете вернуть ноль
или исключение
Но вы должны отметить это в комментарии класса
Добавлено:+ Это более очевидно, чем какой-либо метод расширения