对于我的所有 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 属性.