代码之家  ›  专栏  ›  技术社区  ›  RandomProgrammer

在使用代码契约和Linq to Sql时,如何避免“source!=null”?

  •  6
  • RandomProgrammer  · 技术社区  · 14 年前

    我使用正常的数据上下文编写了以下代码,效果非常好:

    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:需要未经验证的:源!=无效的

    4 回复  |  直到 14 年前
        1
  •  1
  •   koenmetsu    14 年前

    我猜你的警告是由车主参数引起的,而不是汽车。在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的内容。

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

        2
  •  0
  •   Kosala Nuwan Perera    14 年前

    我想知道你是如何用扩展方法编译代码的,因为你不知道 this 方法签名中的关键字。

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

    /金伯利进程

        3
  •  0
  •   Jim Counts    13 年前

    您的代码片段可能没有完全描述您正在使用的代码。

    考虑这个片段,而不是:

    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 )可能是空的。

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

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

    这份合同应该没问题,因为 Where 不会返回null,而是返回 Enumerable.Empty<T>() 当没有匹配的时候。

        4
  •  0
  •   Manuel Fahndrich    11 年前

    我们在几次发布后修复了这个问题。该警告是由于Linq表达式构造等方面缺少一些约定。Linq表达式方法有约定,C#编译器生成调用这些方法的代码。如果我们对调用的方法没有足够的post条件,那么您可能会得到这些关于代码的神秘警告,而您甚至不知道这些代码是否存在(除非您使用ILdasm)。