Count()
扫描所有元素,因此if (list.Count() == 1)
如果enumerable包含很多元素,则效果不佳.
Single()
如果没有一个元素,则抛出异常.使用try { list.Single(); } catch(InvalidOperationException e) {}
是笨拙和低效的.
SingleOrDefault()
如果有多个元素,则抛出异常,因此if (list.SingleOrDefault() == null)
(假设TSource
是引用类型)对大小大于1的可枚举不起作用.
nvo*_*igt 14
var exactlyOne = sequence.Take(2).Count() == 1;
Run Code Online (Sandbox Code Playgroud)
该Take
扩展方法不会抛出,如果有更少的元素,它只会只有那些获得回报.
更直接:
public static bool HasSingle<T>(this IEnumerable<T> sequence) {
if (sequence is ICollection<T> list) return list.Count == 1; // simple case
using(var iter = sequence.GetEnumerator()) {
return iter.MoveNext() && !iter.MoveNext();
}
}
Run Code Online (Sandbox Code Playgroud)
但是请注意,你只能保证你能读一个序列一次,所以在这种情况下:通过检查,有一个简单的事实是一个单一的项目,可以不再获得该项目.所以如果有的话,你可能更喜欢能给你价值的东西:
public static bool HasSingle<T>(this IEnumerable<T> sequence, out T value)
{
if (sequence is IList<T> list)
{
if(list.Count == 1)
{
value = list[0];
return true;
}
}
else
{
using (var iter = sequence.GetEnumerator())
{
if (iter.MoveNext())
{
value = iter.Current;
if (!iter.MoveNext()) return true;
}
}
}
value = default(T);
return false;
}
Run Code Online (Sandbox Code Playgroud)
为了避免其他答案中的额外迭代,您可以实现自己的扩展:
public static bool HasExactlyOneElement<T>(this IEnumerable<T> source)
{
using (var enumerator = source.GetEnumerator())
return enumerator.MoveNext() && !enumerator.MoveNext();
}
Run Code Online (Sandbox Code Playgroud)
您可以使用!Skip(1).Any()
:
bool contains1 = items.Any() && !items.Skip(1).Any();
Run Code Online (Sandbox Code Playgroud)
如果类型是集合,则可以创建一个更有效的扩展:
public static bool ContainsCountItems<TSource>(this IEnumerable<TSource> source, int count)
{
ICollection<TSource> collectionoft = source as ICollection<TSource>;
if (collectionoft != null) return collectionoft.Count == count;
ICollection collection = source as ICollection;
if (collection != null) return collection.Count == count;
int itemCount = 0;
using (IEnumerator<TSource> e = source.GetEnumerator())
{
checked
{
while (e.MoveNext() && ++itemCount <= count)
{
if (itemCount == count)
return !e.MoveNext();
}
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
用法:
var items = Enumerable.Range(0, 1);
bool contains1 = items.ContainsCountItems(1); // true;
items = Enumerable.Range(0, 2);
contains1 = items.ContainsCountItems(1); // false;
Run Code Online (Sandbox Code Playgroud)
您可以将此扩展名使用任何类型和任何数量,因此不仅1
var items = Enumerable.Range(0, 10);
bool contains10 = items.ContainsCountItems(10); // true;
Run Code Online (Sandbox Code Playgroud)
我建议与一起玩Any
,我们必须检查一下
list
至少有一项- Any
list
没有第二项- !list.Skip(1).Any()
码:
bool isSingle = list.Any() && !list.Skip(1).Any();
Run Code Online (Sandbox Code Playgroud)
但是这种方法有一个缺点:它扫描list
两次,以防万一IQueryable
(查询执行两次,结果可能会有所不同,并且会产生额外开销)