2013-02-19 73 views
3

假设以下简单的代码:接口契约混淆静态检查

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

的静态检查是能证明Property将不为空时Method使用它。现在

,我介绍一个接口与合同一起和静态检查开始抱怨:“可能调用空引用‘this.Property’的方法

这是一个错误还是我失去了一些东西?


与接口的代码如下所示:

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

我的设置都像第是:

我得到以下输出:

[...] 
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' 
[...] 

我使用Visual Studio 2010旗舰版和.NET 4的目标框架。

+0

我不能用VS 2012和VS 2010分别用C#5和4编译来重现它。我有相同的代码合同版本和配置。我只收到8个建议保证。我错过了什么吗? – 2013-02-19 16:48:01

+0

@IlyaIvanov:你编译了第一个或第二个代码片段吗?只有第二个片段显示该行为。此外,请确保您的设置与我的设置相同。 – 2013-02-19 16:50:41

+0

我确定,所有的都是一样的。此外,如果我评论'//SetField();'然后我收到'CodeContracts:可能调用空引用方法'this.Property'' – 2013-02-19 16:51:35

回答

0

如果问题仅表现为类内代码 - 这是在我的例子的情况下 - 务实的解决方案很简单:

使用,而不是属性的支持字段:

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

不是一个答案,而是对问题的一些想法。这不是那个接口合同,它混淆了代码合同。我已经设法通过一个简单的例子来重现这一点,没有ContractClass的界面。只需将第二个示例更改为简单

//Foo's declaration 

public interface IFoo 
{ 
    string Property { get; } 
} 

而且您将得到相同的错误。即使在属性字段中添加Contract.Assume(_field != null);也不能解决此问题(它将修复它将此Assume添加到SetField方法)。我没有设法用Invariants抑制空引用异常警告。唯一有效的方法是相当难看的解决方案,您必须为接口合同提供后置条件,并在代码合同的属性字段中提供assume的提示。完整的代码如下所示

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

编辑: 作为_field可以为空,我建议使用这种方法的机身给予提示,分析仪,使其不会与空理会参考警告。

private string Method() 
{ 
    SetField(); 
    Contract.Assume(Property != null); 
    return Property.Trim(); 
} 

p.s.正如John Sonmez在pluralsight training regarding Code contracts上所说的那样“静态分析是一项复杂而神秘的任务,如果没有提示启动Assume方法调用的分析器,那么这个任务几乎无法解决。

+0

感谢您花时间调查它。我知道'Contract.Assume'的必要性。但在这种情况下不能使用它,因为'Property'被允许为'null'。 – 2013-02-19 17:27:56

+0

你可以在Interface契约中使用不变式来检查这个吗?我认为你仍然需要使用一些冗余的语句,这样静态代码anallyser将会得到保证,'Property'不能在这个特定的代码行 – 2013-02-19 17:29:10

+0

中产生null我不确定哪种类型的不变量。你可以如此善良,并用它更新你的代码? – 2013-02-19 17:31:03