C# 有没有办法让代码契约与LINQ一起工作?

C# 有没有办法让代码契约与LINQ一起工作?,c#,.net,linq,code-contracts,C#,.net,Linq,Code Contracts,代码契约不断给我可能对空引用调用方法的机会,对我所有的LINQ语句发出警告,我找不到让它们静音的方法。例如,下面的方法生成两个这样的警告,因为我在访问car对象的Make和Model属性时没有首先检查null public IEnumerable<string> GetCarModelsByMake(string make) { return from car in Cars where car.Make == make

代码契约不断给我可能对空引用调用方法的机会,对我所有的LINQ语句发出警告,我找不到让它们静音的方法。例如,下面的方法生成两个这样的警告,因为我在访问car对象的Make和Model属性时没有首先检查null

    public IEnumerable<string> GetCarModelsByMake(string make)
    {
        return from car in Cars
               where car.Make == make
               select car.Model;
    }
但由于某种原因,这并不能抑制警告。我甚至还尝试了以下SuppressMessage属性,但都不起作用:

    [SuppressMessage("Microsoft.Contracts", "Requires")]
    [SuppressMessage("Microsoft.Contracts", "Ensures")]
    [SuppressMessage("Microsoft.Contracts", "Invariant")]
我甚至尝试使用ContractVerification属性完全禁用方法的合同验证:

    [SuppressMessage("Microsoft.Contracts", "NonNull")]
    [ContractVerification(false)]
但这也不起作用。因此,我决定在LINQ语句的where子句中添加一个显式空检查:

    public IEnumerable<string> GetCarModelsByMake(string make)
    {
        return from car in Cars
               where car != null && car.Make == make
               select car.Model;
    }
这成功地消除了where子句的警告,但并没有消除select子句的警告。事实上,我发现要真正消除这两个警告,唯一的方法是向LINQ语句中的每个子句添加空检查,如下所示:

    public IEnumerable<string> GetCarModelsByMake(string make)
    {
        Contract.Assume(Cars.All(car => car != null));

        return from car in Cars
               where car.Make == make
               select car.Model;
    }
    public IEnumerable<string> GetCarModelsByMake(string make)
    {
        return from car in Cars
               where car != null && car.Make == make
               select car == null ? null : car.Model;
    }

显然,这不是非常干净或高效的代码,我实际上并不打算在我的所有LINQ语句中添加这种冗余的空检查——特别是当我知道枚举不包含任何空条目时。此问题的最佳解决方案是让静态检查器理解契约。假设语句确保集合中的每个项的值均为非null,但如果无法做到这一点,则至少应遵守方法上的SuppressMessage属性。

它可能会抱怨null检查。试试这个:

public IEnumerable GetCarModelsByMake(string make) { if (null == Cars) return new string[0]; // or null if you like return from car in Cars where car.Make == make select car.Model; } 请记住,此LINQ语句实际上与以下语句相同:

return Cars.Where(car => car.Make == make).Select(car => car.Model);
如果Cars为null,则会出现异常。

您是否尝试过最新版本的代码契约?有一个是在10月份发布的,我不能用它来复制


或者,代码契约在static Contracts类上定义了自己的ForAll方法,它的逻辑可能比LINQ extension All方法更好。

+1但我认为添加Cars!=空到类不变量将更接近原始代码的精神,这显然不期望Cars为空。绝对地这个类的不变量更适合这个问题的代码契约性质。我应该澄清一下,这个类已经有了一个保证汽车的不变量!=无效的但这不是合同警告的内容。警告是关于car变量为null,而不是Cars集合。您可以添加另一个类似的不变量吗!汽车,斯努尔?