2013-02-19 69 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