代码契约一直给我“可能在空引用上调用一个方法”警告所有我的LINQ语句,我找不到让它们静音的方法。例如,以下方法生成两个这样的警告,因为我正在访问“car”对象的“Make”和“Model”属性,而不首先检查null。
public IEnumerable<string> GetCarModelsByMake(string make)
{
return from car in Cars
where car.Make == make
select car.Model;
}
在我的特定情况下,我知道Cars集合永远不会包含任何空条目,所以我想我可以在方法中添加一个Assume来静音静态检查器,如下所示:
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;
}
但这不起作用,大概是因为期望静态检查器理解它有点太多了。所以,我决定使用以下SuppressMessage属性来禁止警告:
[SuppressMessage("Microsoft.Contracts", "NonNull")]
但由于某种原因,这无法抑制警告。我甚至尝试了以下SuppressMessage属性,其中没有一个工作:
[SuppressMessage("Microsoft.Contracts", "Requires")]
[SuppressMessage("Microsoft.Contracts", "Ensures")]
[SuppressMessage("Microsoft.Contracts", "Invariant")]
我甚至尝试使用ContractVerification属性完全禁用该方法的合同验证:
[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)
{
return from car in Cars
where car != null && car.Make == make
select car == null ? null : car.Model;
}
显然,这不是非常干净或高效的代码,我实际上并不打算在我的所有LINQ语句中添加这样的冗余空值检查 - 特别是当我知道枚举不包含任何空条目时。解决此问题的最佳方法是让静态检查器了解Contract.Assume语句,以确保集合中每个项目的非空值,但如果无法完成,那么至少要尊重该方法的SuppressMessage属性
答案 0 :(得分:5)
可能会抱怨无效检查汽车。试试这个:
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为空,您将获得异常。
答案 1 :(得分:2)
您是否尝试过最新版本的代码合约?有一个在10月份发布,我无法用它重现。
或者,代码约定在静态ForAll
类上定义了自己的Contracts
方法,它的逻辑可能比LINQ扩展All
方法更好。