如何避免 Linq 链接返回 null?

发布于 2024-09-06 02:50:58 字数 742 浏览 1 评论 0原文

我对代码契约和 linq 有疑问。我设法将问题范围缩小到以下代码示例。现在我被困住了。

public void SomeMethod()
{
    var list = new List<Question>();

    if (list.Take(5) == null) { }
    // resharper hints that condition can never be true

    if (list.ForPerson(12) == null) { }
    // resharper does not hint that condition can never be true
}

public static IQueryable<Question> ForPerson(this IQueryable<Question> source, int personId)
{
    if(source == null) throw new ArgumentNullException();

    return from q in source
           where q.PersonId == personId
           select q;
}

我的 linq 链出了什么问题?为什么 resharper 在分析 ForPerson 调用时不“抱怨”?

编辑:ForPerson方法的返回类型从字符串更改为IQueryable,这就是我的意思。 (我的错)

I have a problem with code contracts and linq. I managed to narrow the issue to the following code sample. And now I am stuck.

public void SomeMethod()
{
    var list = new List<Question>();

    if (list.Take(5) == null) { }
    // resharper hints that condition can never be true

    if (list.ForPerson(12) == null) { }
    // resharper does not hint that condition can never be true
}

public static IQueryable<Question> ForPerson(this IQueryable<Question> source, int personId)
{
    if(source == null) throw new ArgumentNullException();

    return from q in source
           where q.PersonId == personId
           select q;
}

What is wrong with my linq chain? Why doesn't resharper 'complain' when analyzing the ForPerson call?

EDIT: return type for ForPerson method changed from string to IQueryable, which I meant. (my bad)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

情归归情 2024-09-13 02:50:58

Reshaper 正确的是,TakeSkip 的结果永远不会为 null - 如果没有项目,则结果是 IEnumerable,其中没有元素。我认为要做你想做的事你应该检查Any

var query = list.Take(5);
if (!query.Any())
{
    // Code here executes only if there were no items in the list.
}

但这个警告是如何发挥作用的呢?仅通过查看方法定义,Resharper 无法知道该方法永远不会返回 null,并且我假设它不会对方法主体进行反向工程来确定它永远不会返回 null。因此,我认为它已经被专门硬编码,并有一条规则指定 .NET 方法 Skip 和 Take 不返回 null。

当您编写自己的自定义方法时,Reflector 可以从接口对您的方法行为做出假设,但您的接口允许它返回 null。因此它不会发出警告。如果它分析方法主体,那么它可以看到 null 是不可能的,并且能够发出警告。但分析代码以确定其可能的行为是一项极其困难的任务,我怀疑红门是否愿意花钱来解决这个问题,因为他们可以在其他地方以更低的开发成本添加更多有用的功能。

确定布尔表达式是否可以返回true称为布尔可满足性问题,是一个 NP 难问题。

您希望 Resharper 确定通用方法体是否可以返回null。这是上述 NP 难问题的推广。任何工具都不可能在 100% 的情况下正确执行此操作。

Reshaper is correct that the result of a Take or Skip is never null - if there are no items the result is an IEnumerable<Question> which has no elements. I think to do what you want you should check Any.

var query = list.Take(5);
if (!query.Any())
{
    // Code here executes only if there were no items in the list.
}

But how does this warning work? Resharper cannot know that the method never returns null from only looking at the method definition, and I assume that it does not reverse engineer the method body to determine that it never returns null. I assume therefore that it has been specially hard-coded with a rule specifying that the .NET methods Skip and Take do not return null.

When you write your own custom methods Reflector can make assumptions about your method behaviour from the interface, but your interface allows it to return null. Therefore it issues no warnings. If it analyzed the method body then it could see that null is impossible and would be able to issue a warning. But analyzing code to determine its possible behaviour is an incredibly difficult task and I doubt that Red Gate are willing to spend the money on solving this problem when they could add more useful features elsewhere with a much lower development cost.

To determine whether a boolean expression can ever return true is called the Boolean satisfiability problem and is an NP-hard problem.

You want Resharper to determine whether general method bodies can ever return null. This is a generalization of the above mentioned NP-hard problem. It's unlikely any tool will ever be able to do this correctly in 100% of cases.

乖乖 2024-09-13 02:50:58
if(source == null) throw new ArgumentNullException(); 

这不是代码契约方式,您的意思是:

Contract.Require(source != null);
if(source == null) throw new ArgumentNullException(); 

That's not the code contract way, do you instead mean:

Contract.Require(source != null);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文