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

4

我有一个简单的LinQ查询,如下所示:

myList.Where(x=> x.Property.Property2 == 5);

然而,属性可能为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);
    }
}

感谢您的要求。
2个回答

7

是的,您可以像这样扩展 Lambda:

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

当然,这只适用于“正常”的linq。 Linq-to-sql或-entity查询提供程序可能无法将其转换为sql。


7
我不喜欢会导致异常的查询。相比之下,我更喜欢使用循环。然而,我们建议避免在查询表达式中调用任何可能会产生副作用的方法,例如修改数据源内容或抛出异常。来源为:https://msdn.microsoft.com/zh-cn/library/bb513730.aspx - Tim Schmelter
2
@TimSchmelter 我同意,但这是楼主要求的。 - René Vogt
1
@TimSchmelter myList.Where(x=> x.Property?.Property2 == 5); 的问题是什么? - Royi Namir
1
@RoyiNamir 那个 OP 想要 抛出一个 ArgumentNullException,而不是 避免 它。 - René Vogt
1
谢谢,那我会遵循使用循环的建议。谢谢。 - Álvaro García
显示剩余2条评论

7
我会避免使用异常。您可以使用新的C#6空值传播运算符:
myList.Where(x=> x.Property?.Property2 == 5);

或者这种简单的方法:
 myList.Where(x=> x.Property != null && x.Property.Property2 == 5);

然而,如果你真的想要抛出异常,我会使用一个简单的循环,这也更容易调试。这是推荐的,因为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);
}
// ...

Rene 展示了另一种方法,我不建议抛出异常。这在像 Linq-To-SqlLinq-To-Entities 这样的 LINQ 提供程序中无法翻译,并违反了上述准则。

更新:也许像这样的 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;
    }
}

你会这样使用它:
List<MyType> myLstresult = myList
    .ThrowIfArgumentNull(x => x.Property, "MyType.Property")
    .Where(x => x.Property.Property2 == 5)
    .ToList();

你可以先将数据分成有效和无效两部分,并在循环后检查空值。这取决于数据量的大小以及是否需要在发现空值时立即抛出异常。 - Andre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接