是否可以在LinQ中使用条件内部where子句?

Álv*_*cía 4 .net c# linq

我有这样一个简单的LinQ查询:

myList.Where(x=> x.Property.Property2 == 5);
Run Code Online (Sandbox Code Playgroud)

但是,Property可能为null,然后我收到错误.所以我想知道是否有任何方法可以检查它是否为null,如果不为null,则执行比较,如果为null,则抛出异常.

因为如果没有,我必须使用foreach来检查每个元素,这样:

List<MyType> myLstResult = new List<MyType>();
foreach(MyType iterator in myList)
{
    if(iterator.Property == null)
    {
        throw new ArgumentNullException();
    }
    if(iterator.Property.Property2 == 5)
    {
        myLstresult.Add(iterator);
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢.

Ren*_*ogt 7

是的你可以像这样扩展lambda:

myList.Where(x=> 
    {
        if (x.Property == null)
            throw new ArgumentNullException();
        return x.Property.Property2 == 5;
    });
Run Code Online (Sandbox Code Playgroud)

这当然只适用于"普通"linq.Linq-to-sql或-entity查询提供程序可能无法将其转换为sql.

  • 我不喜欢导致异常的查询.我当然更喜欢循环._"但是,我们建议您避免在查询表达式中调用任何可能产生副作用的方法,例如修改数据源的内容或**抛出异常**"_ https://msdn.microsoft.com /en-us/library/bb513730.aspx (7认同)
  • @TimSchmelter我同意,但这就是OP要求的. (2认同)

Tim*_*ter 7

我会避免例外.

您可以使用新的C#6空传播运算符:

myList.Where(x=> x.Property?.Property2 == 5);
Run Code Online (Sandbox Code Playgroud)

或者这个简单的方法:

 myList.Where(x=> x.Property != null && x.Property.Property2 == 5);
Run Code Online (Sandbox Code Playgroud)

但是,如果你真的想抛出一个异常,我会使用一个更容易调试的普通循环.建议这样做,因为LINQ查询不应导致副作用或抛出异常:

https://msdn.microsoft.com/en-us/library/bb513730.aspx

但是,我们建议您避免在查询表达式中调用任何可能产生副作用的方法,例如修改数据源的内容或抛出异常

所以foreach你已经展示过的循环(我最喜欢的)或者try-catch:

List<MyType> myLstResult = null;
try
{
    myLstResult = myList.Where(x=> x.Property.Property2 == 5).ToList();
}
catch(NullReferenceException nullref)
{
    throw new ArgumentNullException("MyType.Property must not be null", nullref);
}
// ...
Run Code Online (Sandbox Code Playgroud)

Rene已经展示了另一种我不建议抛出异常的方法.这不能从LINQ提供商那样翻译,Linq-To-Sql或者Linq-To-Entities违反上述指南.

更新:也许ThrowIfArgumentNull像这样的扩展方法派上用场:

public static IEnumerable<TSource> ThrowIfArgumentNull<TSource, TNullable>(this IEnumerable<TSource> enumeration, Func<TSource, TNullable> mightBeNullSelector, string argumentName) 
    where TNullable : class
{
    foreach (TSource item in enumeration)
    {
        if (mightBeNullSelector(item) == null)
            throw new ArgumentNullException(argumentName);
        yield return item;
    }
}
Run Code Online (Sandbox Code Playgroud)

你会以这种方式使用它:

List<MyType> myLstresult = myList
    .ThrowIfArgumentNull(x => x.Property, "MyType.Property")
    .Where(x => x.Property.Property2 == 5)
    .ToList();
Run Code Online (Sandbox Code Playgroud)