有没有办法让代码契约与LINQ一起使用?

Jam*_*ger 2 .net c# linq code-contracts

代码契约一直给我"可能在空引用上调用一个方法"警告所有我的LINQ语句,我找不到一种方法来使它们静音.例如,以下方法生成两个这样的警告,因为我正在访问"car"对象的"Make"和"Model"属性,而不首先检查null.

    public IEnumerable<string> GetCarModelsByMake(string make)
    {
        return from car in Cars
               where car.Make == make
               select car.Model;
    }
Run Code Online (Sandbox Code Playgroud)

在我的特定情况下,我知道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;
    }
Run Code Online (Sandbox Code Playgroud)

但这不起作用,大概是因为期望静态检查器理解它有点太多了.所以,我决定使用以下SuppressMessage属性来禁止警告:

    [SuppressMessage("Microsoft.Contracts", "NonNull")]
Run Code Online (Sandbox Code Playgroud)

但由于某种原因,这无法抑制警告.我甚至尝试了以下SuppressMessage属性,其中没有一个工作:

    [SuppressMessage("Microsoft.Contracts", "Requires")]
    [SuppressMessage("Microsoft.Contracts", "Ensures")]
    [SuppressMessage("Microsoft.Contracts", "Invariant")]
Run Code Online (Sandbox Code Playgroud)

我甚至尝试使用ContractVerification属性完全禁用该方法的合同验证:

    [ContractVerification(false)]
Run Code Online (Sandbox Code Playgroud)

但这也不起作用.所以,我决定在LINQ语句的"where"子句中添加一个显式的空检查:

    public IEnumerable<string> GetCarModelsByMake(string make)
    {
        return from car in Cars
               where car != null && car.Make == make
               select car.Model;
    }
Run Code Online (Sandbox Code Playgroud)

这成功地消除了"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;
    }
Run Code Online (Sandbox Code Playgroud)

显然,这不是非常干净或高效的代码,我实际上并不打算在我的所有LINQ语句中添加这样的冗余空值检查 - 特别是当我知道枚举不包含任何空条目时.解决此问题的最佳方法是让静态检查器了解Contract.Assume语句,以确保集合中每个项目的非空值,但如果无法完成,那么至少要尊重该方法的SuppressMessage属性.

Tra*_*man 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为null,您将获得异常.