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.

+3


source to share


2 answers


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

      

0


source


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."

+1


source







All Articles