Interface contract confuses static validation
Let's assume the following is simple code:
public class Foo // : IFoo
{
private string _field;
public string Property
{
get { return _field; }
}
private void SetField()
{
_field = " foo ";
}
private string Method()
{
SetField();
return Property.Trim();
}
}
A static checker can prove Property
it will not be null if Method
used.
Now I present an interface along with a contract, and the static controller starts complaining, "Perhaps a method call on a null reference" this.Property ".
Is this a bug or am I missing something?
The code with the interface looks like this:
public class Foo : IFoo
{
private string _field;
public string Property
{
get { return _field; }
}
private void SetField()
{
_field = " foo ";
}
private string Method()
{
SetField();
return Property.Trim();
}
}
[ContractClass(typeof(IFooContract))]
public interface IFoo
{
string Property { get; }
}
[ContractClassFor(typeof(IFoo))]
public abstract class IFooContract : IFoo
{
public string Property
{
get { throw new System.NotImplementedException(); }
}
}
My settings:
I am getting the following output:
[...]
C:\{path}\CC2.cs(11,19): message : CodeContracts: Suggested ensures: Contract.Ensures(Contract.Result<System.String>() == this._field);
C:\{path}\CC2.cs(16,13): message : CodeContracts: Suggested ensures: Contract.Ensures(this._field != null);
C:\{path}\CC2.cs(21,13): message : CodeContracts: Suggested ensures: Contract.Ensures(Contract.Result<System.String>() != null);
C:\{path}\CC2.cs(21,13): message : CodeContracts: Suggested ensures: Contract.Ensures(this._field != null);
C:\{path}\CC2.cs(21,13): message : CodeContracts: Suggested ensures: Contract.Ensures(this.Property.Trim() != null);
C:\{path}\CC2.cs(21,13): message : CodeContracts: Suggested ensures: Contract.Ensures(Contract.Result<System.String>() == this.Property.Trim());
[...]
C:\{path}\CC3.cs(33,13): warning : CodeContracts: Possibly calling a method on a null reference 'this.Property'
[...]
I am using Visual Studio 2010 Ultimate with .NET 4 as my target environment.
source to share
If the problem only manifests itself for the code within the class - as is the case in my example - the pragmatic solution is simple:
Use a backing field instead of a property:
public class Foo : IFoo
{
private string _field;
public string Property
{
get { return _field; }
}
private void SetField()
{
_field = " foo ";
}
private string Method()
{
SetField();
return _field.Trim();
}
}
source to share
Not really an answer, but some thoughts on the matter. This is not the interface contract that Code Contracts confuses. I was able to reproduce this with a simple example without ContractClass
for the interface. Just change the second example to simple
//Foo declaration
public interface IFoo
{
string Property { get; }
}
And you will get the same error. Even adding Contract.Assume(_field != null);
in the Property does not correct his field (he will fix it by adding this method Assume
to SetField
). I was also unable to suppress the link exclusion warning with Invariants. The only thing that worked was a rather ugly solution where you need to provide postconditioning for the interface contract and give the code contract a hint with a field Assume
in the Properties field. The complete code is shown below
public class Foo : IFoo
{
private string _field;
public string Property
{
get
{
Contract.Assume(_field != null);
return _field;
}
}
private void SetField()
{
_field = " foo ";
}
private string Method()
{
SetField();
return Property.Trim();
}
}
[ContractClass(typeof(IFooContract))]
public interface IFoo
{
string Property { get; }
}
[ContractClassFor(typeof(IFoo))]
public abstract class IFooContract : IFoo
{
public string Property
{
get
{
Contract.Ensures(Contract.Result<string>() != null);
throw new NotImplementedException();
}
}
}
Edit: Since it _field
can be null, I suggest using this method to give hints to the parser so that it doesn't bother with a null audit warning.
private string Method()
{
SetField();
Contract.Assume(Property != null);
return Property.Trim();
}
ps as John Sonmez says in the section on plural training about code contracts "Static analysis is a complex, cryptic task that can hardly be developed without hints of a suing parser. Assume method calls."
source to share