2

我对代码合同和 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 链有什么问题?为什么在分析 ForPerson 调用时不重新分析“抱怨”?

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

4

2 回答 2

4

Reshaper 是正确的, a Takeor的结果Skip永远不会为空 - 如果没有项目,则结果是一个IEnumerable<Question>没有元素的结果。我认为做你想做的事你应该检查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 是不可能的,并且能够发出警告。但是分析代码以确定其可能的行为是一项非常困难的任务,我怀疑 Red Gate 是否愿意花钱解决这个问题,因为他们可以在其他地方以更低的开发成本添加更多有用的功能。

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

您希望 Resharper 确定通用方法主体是否可以返回null。这是上述 NP-hard 问题的推广。在 100% 的情况下,任何工具都不可能正确地做到这一点。

于 2010-06-19T10:10:33.593 回答
0
if(source == null) throw new ArgumentNullException(); 

这不是代码合同的方式,你的意思是:

Contract.Require(source != null);
于 2010-06-19T15:51:24.523 回答