How to avoid “source !=null” when using Code Contracts and Linq To Sql?

▼魔方 西西 提交于 2019-12-01 03:29:21

问题


I have the following code using a normal data context which works great:

var dc = new myDataContext();
Contract.Assume(dc.Cars!= null);
var cars = (from c in dc.Cars
            where c.Owner == 'Jim'
            select c).ToList();

However when I convert the filter to an extension method like this:

var dc = new myDataContext();
Contract.Assume(dc.Cars!= null);
var cars = dc.Cars.WithOwner('Jim');

public static IQueryable<Car> WithOwner(this IQueryable<Car> cars, string owner)
{
    Contract.Requires(cars != null);
    return cars.Where(c => c.Owner == owner);
}

I get the following warning:

warning : CodeContracts: requires unproven: source != null


回答1:


My guess is that your warning is caused by the owner parameter, rather than the cars. Add a precondition in the WithOwner method to check if owner is not null.

public static IQueryable<Car> WithOwner(IQueryable<Car> cars, string owner)
{
    Contract.Requires(cars != null);
    Contract.Requires(!string.isNullOrEmpty(owner));
    return cars.Where(c => c.Owner = owner);
}

In your first code sample, you have 'Jim' hard-coded, so no problems there because there is not something which can be null.

In your second example you created a method for which the static compiler cannot prove that the source ( being owner ) 'will never be null', as other code might call it with an invalid values.




回答2:


I wonder how you get the code compiled with the Extension method since you are missing this keyword in your method signature.

public static IQueryable<Car> WithOwner(this IQueryable<Car> cars, string owner)
{
    ...
}

/KP




回答3:


Its possible that your code snippet does not completely describe the code you are using.

Consider this snippet instead:

var dc = new myDataContext();
Contract.Assume(dc.Cars!= null);
var models = dc.Cars.WithOwner('Jim').Select(c => c.Model);

public static IQueryable<Car> WithOwner(this IQueryable<Car> cars, string owner)
{
    Contract.Requires(cars != null);
    return cars.Where(c => c.Owner == owner);
}

In this snipped its likely the runtime will complain with the warning you mentioned, but it is not complaining about Cars possibly being null, it is complaining about the result from WithOwner (passed into Select) possibly being null.

You can satisfy the runtime by ensuring that the result from your extension method will not be null:

Contract.Ensures(Contract.Result<IQueryable<Car>>() != null);

This contract should be ok because Where will not return null, but instead returns an Enumerable.Empty<T>() when there are no matches.




回答4:


We fixed this a few releases back. The warning was due to some missing contracts around Linq expression construction etc. Linq expression methods have contracts and the C# compiler generates code that calls these methods. If we don't have enough post conditions on the called methods, then you can get these cryptic warnings about code that you don't even know is there (unless you look with ILdasm).



来源:https://stackoverflow.com/questions/3050279/how-to-avoid-source-null-when-using-code-contracts-and-linq-to-sql

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!