6

我有以下代码使用正常的数据上下文,效果很好:

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:需要未经证实:来源!= null

4

4 回答 4

1

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

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”进行了硬编码,因此没有问题,因为没有可以为空的东西。

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

于 2010-06-18T11:35:16.610 回答
0

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

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

/KP

于 2010-08-15T16:21:28.370 回答
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(传递给Select)的结果可能为空。

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

Contract.Ensures(Contract.Result<IQueryable<Car>>() != null);

这个合约应该没问题,因为Where不会返回 null,而是Enumerable.Empty<T>()在没有匹配项时返回 an。

于 2011-09-12T21:08:29.130 回答
0

我们在几个版本中修复了这个问题。警告是由于 Linq 表达式构造等缺少一些契约。Linq 表达式方法具有契约,C# 编译器生成调用这些方法的代码。如果我们在调用的方法上没有足够的后置条件,那么您可能会收到这些关于您甚至不知道存在的代码的神秘警告(除非您使用 ILdasm 查找)。

于 2013-04-25T19:20:45.620 回答