使用Code Contracts和Linq To Sql时如何避免“source!= null”?

时间:2010-06-16 02:05:21

标签: linq-to-sql code-contracts

我使用正常数据上下文的代码如下:

var dc = new myDataContext();
Contract.Assume(dc.Cars!= null);
var cars = (from c in dc.Cars
            where c.Owner == 'Jim'
            select c).ToList();

但是当我将过滤器转换为这样的扩展方法时:

var dc = new myDataContext();
Contract.Assume(dc.Cars!= null);
var cars = dc.Cars.WithOwner('Jim');

public static IQueryable<Car> WithOwner(this IQueryable<Car> cars, string owner)
{
    Contract.Requires(cars != null);
    return cars.Where(c => c.Owner == owner);
}

我收到以下警告:

  

警告:CodeContracts:需要unproven:source!= null

4 个答案:

答案 0 :(得分:1)

我的猜测是你的警告是由所有者参数引起的,而不是汽车引起的。在WithOwner方法中添加前提条件以检查owner是否为null。

public static IQueryable<Car> WithOwner(IQueryable<Car> cars, string owner)
{
    Contract.Requires(cars != null);
    Contract.Requires(!string.isNullOrEmpty(owner));
    return cars.Where(c => c.Owner = owner);
}

在你的第一个代码示例中,你有'Jim'硬编码,所以没有问题因为没有可以为null的东西。

在第二个示例中,您创建了一个方法,静态编译器无法证明源(所有者)'永远不会为空',因为其他代码可能会使用无效值来调用它。

答案 1 :(得分:0)

我想知道如何使用Extension方法编译代码,因为您在方法签名中缺少 this 关键字。

public static IQueryable<Car> WithOwner(this IQueryable<Car> cars, string owner)
{
    ...
}

/ KP

答案 2 :(得分:0)

您的代码段可能无法完整描述您正在使用的代码。

请考虑以下代码:

var dc = new myDataContext();
Contract.Assume(dc.Cars!= null);
var models = dc.Cars.WithOwner('Jim').Select(c => c.Model);

public static IQueryable<Car> WithOwner(this IQueryable<Car> cars, string owner)
{
    Contract.Requires(cars != null);
    return cars.Where(c => c.Owner == owner);
}

在此剪切中,运行时可能会抱怨您提到的警告,但它并没有抱怨Cars可能为空,它抱怨来自WithOwner的结果(传递给{{ 1}})可能为null。

您可以通过确保扩展方法的结果不为null来满足运行时:

Select

此合约应该没问题,因为Contract.Ensures(Contract.Result<IQueryable<Car>>() != null); 不会返回null,而是在没有匹配时返回Where

答案 3 :(得分:0)

我们修复了几个版本。警告是由于Linq表达式构造等方面缺少一些合同.Linq表达方法有契约,C#编译器生成调用这些方法的代码。如果我们对被调用的方法没有足够的后置条件,那么你可以得到关于你甚至不知道的代码的这些神秘警告(除非你看看ILdasm)。