C# 有没有办法让代码契约与LINQ一起工作?
代码契约不断给我可能对空引用调用方法的机会,对我所有的LINQ语句发出警告,我找不到让它们静音的方法。例如,下面的方法生成两个这样的警告,因为我在访问car对象的Make和Model属性时没有首先检查nullC# 有没有办法让代码契约与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
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集合。您可以添加另一个类似的不变量吗!汽车,斯努尔?