2

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

4

2 回答 2

5

它可能会抱怨空检查 Cars。尝试这个:

公共 IEnumerable GetCarModelsByMake(字符串制作)
{
    如果(空==汽车)
        返回新字符串[0];// 或者如果你喜欢 null

    从汽车返回
        哪里 car.Make == 制作
        选择汽车。型号;
}

请记住,此 LINQ 语句实际上与以下内容相同:

return Cars.Where(car => car.Make == make).Select(car => car.Model);

如果 Cars 为空,你会得到一个异常。

于 2009-09-24T19:51:46.947 回答
2

您是否尝试过最新版本的代码合同?10 月份发布了一个,我无法用它复制它。

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

于 2009-11-05T12:43:57.620 回答