Is there a way to make Code Contracts work with LINQ?

Code contracts keep giving me "Possibly method call on null reference" warnings for all my LINQ statements, and I can't find a way to disable them. For example, the following method generates two such warnings because I access the Make and Model properties of the car object without first checking for a null value.

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

      

In my particular case, I know that the Cars collection will never contain any null entries, so I figured I could just add an Accept method to the method to silence the static check, for example:

    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;
    }

      

But that doesn't work, presumably because it's too much to expect the static controller to understand. So, I decided to just suppress the warnings using the following SuppressMessage attribute:

    [SuppressMessage("Microsoft.Contracts", "NonNull")]

      

But for some reason, this cannot suppress the warnings. I even tried the following SuppressMessage attributes, none of which worked:

    [SuppressMessage("Microsoft.Contracts", "Requires")]
    [SuppressMessage("Microsoft.Contracts", "Ensures")]
    [SuppressMessage("Microsoft.Contracts", "Invariant")]

      

I even tried to completely disable contract validation for a method using the ContractVerification attribute:

    [ContractVerification(false)]

      

But that didn't work either. So I figured I'd just add an explicit null check in the "where" clause of the LINQ statement:

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

      

This successfully removes the warning in the "where" clause, but it does not remove the warning for the "select" clause. In fact, the only way I've found to get rid of both warnings is to add null checks to every clause in the LINQ statement, like so:

    public IEnumerable<string> GetCarModelsByMake(string make)
    {
        return from car in Cars
               where car != null && car.Make == make
               select car == null ? null : car.Model;
    }

      

Obviously, this is not very clean or efficient code, and I'm not really going to add such redundant null checks to all my LINQ operators, especially when I know the enumeration does not contain any null entries. The best solution to this problem would be for the static validator to understand the Contract.Assume conventions that enforce nonzero values ​​for every item in the collection, but if that can't be done, then at least read the SuppressMessage attribute for the method.

+2


source to share


2 answers


He may be complaining about zero check of cars. Try the following:

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;
}

Remember that this LINQ operator is actually the same as:



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

You will get an exception if Cars is null.

+5


source


Have you tried the latest Code Contracts? One was released in October and I cannot reproduce it with it.



Alternatively, Code Contracts has its own method ForAll

defined in a static class Contracts

that can work better with its logic than the LINQ extension method All

.

+2


source







All Articles