【问题标题】:How to avoid "source !=null" when using Code Contracts and Linq To Sql?使用 Code Contracts 和 Linq To Sql 时如何避免“source !=null”?
【发布时间】:2010-06-16 02:05:20
【问题描述】:

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

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

【问题讨论】:

    标签: linq-to-sql code-contracts


    【解决方案1】:

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

    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 所有者。我的赌注是c==null,即不能保证cars 中的所有项目都不为空。
    【解决方案2】:

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

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

    /KP

    【讨论】:

      【解决方案3】:

      您的代码 sn-p 可能没有完全描述您正在使用的代码。

      请考虑这个 sn-p:

      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&lt;T&gt;()

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 2010-09-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多