2013-02-26 46 views
9

मान लें निम्न कोड के साथ संयोजन में एक और संपत्ति का संदर्भ:Unproven सुनिश्चित करें कि एक अंतरफलक

[ContractClass(typeof(ICC4Contract))] 
public interface ICC4 
{ 
    bool IsFooSet { get; } 
    string Foo { get; } 
} 

public class CC4 : ICC4 
{ 
    private string _foo; 

    public bool IsFooSet { get { return Foo != null; } } 

    public string Foo { get { return _foo; } } 
} 

[ContractClassFor(typeof(ICC4))] 
public abstract class ICC4Contract : ICC4 
{ 
    public bool IsFooSet 
    { 
     get 
     { 
      Contract.Ensures((Contract.Result<bool>() && Foo != null) 
          || !Contract.Result<bool>()); 
      return false; 
     } 
    } 

    public string Foo 
    { 
     get 
     { 
      Contract.Ensures((Contract.Result<string>() != null && IsFooSet) 
          || !IsFooSet); 
      return null; 
     } 
    } 
} 

ठेके कहने के लिए प्रयास करें:

  1. IsFooSet वापस आ जाएगी true अगर Foonull नहीं है।
  2. Foonull वापस नहीं आता है अगर IsFooSettrue देता है।

यह लगभग काम करता है।
हालांकि, मुझे return _foo; पर "अनुचित" सुनिश्चित होता है, क्योंकि चेकर को यह नहीं पता कि Foo हमेशा _foo के बराबर होगा।

Fooprivate सेटर के साथ स्वचालित संपत्ति में बदलना उस चेतावनी को हटा देता है, लेकिन मैं ऐसा नहीं करना चाहता (मुझे निजी सेटर्स के साथ स्वचालित गुण पसंद नहीं हैं)।

_foo फ़ील्ड को संरक्षित करते समय चेतावनी को दूर करने के लिए मुझे उपरोक्त कोड में क्या बदलना है?

निम्नलिखित काम नहीं करता:

  1. IsFooSet बदलने _foo बजाय Foo उपयोग करने के लिए। इसके परिणामस्वरूप IsFooSet पर एक अतिरिक्त "अनुचित" सुनिश्चित होगा।
  2. एक invariant Foo == _foo जोड़ना। इसके परिणामस्वरूप अंतर्निहित, डिफ़ॉल्ट कन्स्ट्रक्टर पर "अनियंत्रित" अविवाहित होगा। इसके अलावा, वास्तविक कोड-बेस पर स्थैतिक चेकर का प्रसंस्करण समय अधिक हो जाएगा।
  3. Foo के this answer के गेटटर को Contract.Ensures(Contract.Result<string>() == _foo); जोड़ना कुछ भी नहीं बदलेगा।
+1

यह अपनी समस्या के साथ मदद नहीं करेगा, लेकिन मैं आप से पूछना तुम क्यों पसंद नहीं है हो सकता है निजी सेटर्स के साथ स्वचालित गुण? – ken2k

+1

अधिकांश समय, वे गुण एक वर्ग के आविष्कार होते हैं, यानी बैकिंग फ़ील्ड को केवल पढ़ा जाना चाहिए। एक स्वचालित संपत्ति के साथ यह संभव नहीं है। मैं वास्तव में स्वचालित गुणों से पूरी तरह से बचने की कोशिश करता हूं। कारणों को रेखांकित किया गया है [यहां] (http://blog.ploeh.dk/2011/05/26/CodeSmellAutomaticProperty.aspx)। –

+0

यदि आप डिफ़ॉल्ट रूप से खाली स्ट्रिंग पर '_foo' सेट करते हैं तो इसे हटा दिया जाएगा? ऐसा लगता है कि समस्या यह है कि '_foo' का डिफ़ॉल्ट मान' शून्य 'होने जा रहा है। –

उत्तर

2

आप शॉर्ट सर्किट का उपयोग कर सकते हालत आसान बनाने के लिए, और है कि किसी कारण से काम करता है:

[ContractClassFor(typeof(ICC4))] 
public abstract class ICC4Contract : ICC4 
{ 
    public bool IsFooSet 
    { 
     get 
     { 
      Contract.Ensures(!Contract.Result<bool>() || Foo != null); 
      return false; 
     } 
    } 

    public string Foo 
    { 
     get 
     { 
      Contract.Ensures(!IsFooSet || Contract.Result<string>() != null); 
      return null; 
     } 
    } 
}