每当我像这样获取
时,我都会收到异常Feature f = o.Features.SingleOrDefault(e => e.LinkName == PageLink);
因为这可以返回一个或多个元素。我可以用什么方法来解决这个问题?
答案 0 :(得分:29)
Single和SingleOrDefault用于在序列中存在多个匹配项时抛出。其结果是必须在完成之前迭代整个序列。听起来这不是你想要的。请尝试使用FirstOrDefault:
Feature f = o.Features
.FirstOrDefault(e => e.vcr_LinkName == PageLink && e.bit_Activate == true);
这将(通常)表现更好,因为一旦找到匹配就会完成。
当然,如果你真的想要保留多个元素,那么Where子句会更合适:
IEnumerable<Feature> fs = o.Features
.Where(e => e.vcr_LinkName == PageLink && e.bit_Activate == true);
答案 1 :(得分:20)
或者,如果你只想要一个匹配的项目,并且当有多个匹配时不想抛出,那么这很容易实现。我在我的项目中为此创建了一个扩展方法:
public static class QueryableExtensions
{
public static TSource SingleWhenOnly<TSource>(this IQueryable<TSource> source)
{
if (source == null)
throw new ArgumentNullException("source");
var results = source.Take(2).ToArray();
return results.Length == 1 ? results[0] : default(TSource);
}
public static TSource SingleWhenOnly<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
{
if (source == null)
throw new ArgumentNullException("source");
if (predicate == null)
throw new ArgumentNullException("predicate");
var results = source.Where(predicate).Take(2).ToArray();
return results.Length == 1 ? results[0] : default(TSource);
}
}
答案 2 :(得分:13)
如果您只想要第一个元素,请改用FirstOrDefault
。
基本上,以下是有效结果的选项(即您不想扔的地方)以及使用方法:
Single
SingleOrDefault
First
FirstOrDefault
(ElementAt
和ElementAtOrDefault
,Last
和LastOrDefault
也可用。)
答案 3 :(得分:5)
我发现如果没有一个元素(即零,两个或更多)比我需要正常SingleOrDefault
行为更多,我需要返回默认值的行为,所以这里是我的改编版本Pieter van Ginkel's answer:
public static class LinqExtensions
{
/// <summary>
/// Returns the only element of a sequence, or a default value if the sequence is empty or contains more than one element.
/// </summary>
public static TSource SingleOrDefaultIfMultiple<TSource>(this IEnumerable<TSource> source)
{
var elements = source.Take(2).ToArray();
return (elements.Length == 1) ? elements[0] : default(TSource);
}
/// <summary>
/// Returns the only element of a sequence, or a default value if the sequence is empty or contains more than one element.
/// </summary>
public static TSource SingleOrDefaultIfMultiple<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
return source.Where(predicate).SingleOrDefaultIfMultiple();
}
/// <summary>
/// Returns the only element of a sequence, or a default value if the sequence is empty or contains more than one element.
/// </summary>
public static TSource SingleOrDefaultIfMultiple<TSource>(this IQueryable<TSource> source)
{
var elements = source.Take(2).ToArray();
return (elements.Length == 1) ? elements[0] : default(TSource);
}
/// <summary>
/// Returns the only element of a sequence, or a default value if the sequence is empty or contains more than one element.
/// </summary>
public static TSource SingleOrDefaultIfMultiple<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
{
return source.Where(predicate).SingleOrDefaultIfMultiple();
}
}
我省略了null参数检查,因为我可以依赖Take
和Where
调用在参数为null时抛出异常,但你可能会感觉不同。
答案 4 :(得分:4)
SingleOrDefault
表示您希望查询的结果为0或1。如果您的数据超过1,那么您的数据或查询就会出现问题。
如果您期望获得超过1个结果而只想要第一个结果,则应使用FirstOrDefault
。
答案 5 :(得分:2)
Single
表示您希望成为序列中的一个元素。
SingleOrDefault
表示您希望序列中有一个或零个元素。
当你想知道有一个(或零)时,你应该使用它,并且当它返回多个时你想要它崩溃。
如果您只是一个,请按照上面的建议使用First
(或FirstOrDefault
),但请确保您正确订购数据。
答案 6 :(得分:1)
如果您使用SingleOrDefault,如果条件满足超过结果,则会抛出错误。
您可以使用FirstOrDefault
来达到结果