2013-02-15 17 views
14

मैं इस तरह नमूना उपयोग कुछ के लिए देख रहा हूँ होने के लिए सामान्य:विवश एक नल प्रकार

Foo<string> stringFoo = new Foo<string>("The answer is"); 
Foo<int> intFoo = new Foo<int>(42); 
// The Value of intFoo & stringFoo are strongly typed 
stringFoo.Nullify(); 
intFoo.Nullify(); 
if (stringFoo == null && intFoo == null) 
    MessageBox.Show("Both are null); 

इस वर्ग फू देखते हुए, मैं कर सकते हैं एक नल में ऑटो चादर टी:

public class Foo1<T> 
    where T : struct 
{ 
    private T? _value; 

    public Foo(T? initValue) 
    { 
     _value = initValue; 
    } 

    public T? Value { get { return _value; } } 

    public void Nullify { _value = null; } 

} 

यह primitives के लिए काम करता है, लेकिन स्ट्रिंग या अन्य कक्षाओं के साथ नहीं।

अगला स्वाद स्ट्रिंग्स के लिए काम करता है, लेकिन नहीं पुरातन:

public class Foo2<T> 
{ 
    private T _value; 

    public Foo(T initValue) 
    { 
     _value = initValue; 
    } 

    public T Value { get { return _value; } } 

    public void Nullify { _value = default(T); } 

} 

मैं foo2 के लिए Nullable<int> इस्तेमाल कर सकते हैं और कोड इस तरह काम करेगा:

Foo2<int?> intFoo = new Foo<int?>(42); 

लेकिन इस त्रुटि होने का खतरा है, क्योंकि यह विफल रहता है Foo2 के लिए। अगर मैं टी को ऐसे प्रकार के रूप में रोक सकता हूं जो शून्यता का समर्थन करते हैं तो यह ठीक होगा।

तो इसके बाद, टी को एक निरर्थक प्रकार होने के लिए बाध्य करने का कोई तरीका है?

कुछ अतिरिक्त नोट्स: .NET 4.0, VS2010। और मुझे यहां पर एक समान प्रश्न मिला, लेकिन एक सफल जवाब के बिना।

उत्तर

9

आप अपेक्षा करते हैं कि नई उदाहरणों केवल एक कारखाने वर्ग के माध्यम से बनाया जा सकता है Foo<T> आंतरिक की निर्माता बनाने के लिए सक्षम हो सकता है, और:

public class Foo<T> 
{ 
    private T value; 
    internal Foo(T value) 
    { 
     this.value = value; 
    } 

    public void Nullify() 
    { 
     this.value = default(T); 
    } 

    public T Value { get { return this.value; } } 
} 

public class Foo 
{ 
    public static Foo<T> Create<T>(T value) where T : class 
    { 
     return new Foo<T>(value); 
    } 

    public static Foo<T?> Create<T>(T? value) where T : struct 
    { 
     return new Foo<T?>(value); 
    } 
} 
+0

दिलचस्प। वास्तविक जीवन में फू अधिक जटिल है और स्वचालित रूप से एक ढांचे द्वारा बनाया गया है। मुझे यह देखने की आवश्यकता होगी कि इस दृष्टिकोण को व्यवहार्य बनाने के लिए ऑब्जेक्ट्स बनाए जाने के तरीके को हुक/अनुकूलित करने का कोई तरीका है या नहीं। – tcarvin

+0

स्वीकृत, क्योंकि यह लाइब्रेरी के आंतरिक ग्राहक (डिजाइन/संकलन समय बनाम रनटाइम) को कम से कम आश्चर्य देता है। लेकिन @ जोन्स स्केट द्वारा उपयोग किया गया परीक्षण भी बहुत अच्छा था! – tcarvin

17

कोई बाधा तो आप इस के लिए आवेदन कर सकते हैं, लेकिन आप निष्पादन समय पर इसके लिए परीक्षण कर सकते हैं:

if (default(T) != null) 
{ 
    throw new SomeAppropriateException(typeof(T) + " is not a nullable type"); 
} 

तुम भी डाल सकता है कि एक स्थिर निर्माता है, जो होगा में यकीन है कि यह केवल मार डाला एक बार प्रति निर्मित प्रकार - और Foo<int> का उपयोग करने का प्रयास करने वाले किसी भी व्यक्ति को TypeInitializerException को अनदेखा करने में कठिनाई होगी। यह सार्वजनिक एपीआई के लिए बहुत अनुकूल नहीं है, लेकिन मुझे लगता है कि यह एक आंतरिक के लिए उचित है।

संपादित करें: एक यह मुश्किल Foo<int> के उदाहरण बनाने के लिए बनाने का भयानक तरीका नहीं है ... आप (डिफ़ॉल्ट मापदंडों और विवश सामान्य प्रकार के एक जोड़े के साथ का उपयोग कर अधिभार संकल्प नियम) ghastly code in this blog post इस्तेमाल कर सकते हैं और निशान अधिभार जो एक गैर-शून्य मूल्य मान प्रकार को एक त्रुटि के साथ अप्रचलित के रूप में लक्षित करता है। इस तरह, Foo<int> अभी भी एक वैध प्रकार होगा, लेकिन आप इसका उदाहरण बनाने के लिए कड़ी मेहनत करेंगे। मेरा सुझाव है कि आप इस हालांकि कर नहीं जा रहा हूँ ...

+0

@ निकोलयखिल: जिस टिप्पणी का आप यहां जवाब दे रहे हैं वह समाप्त हो गया है, लेकिन इस उत्तर में कोड * int 'के लिए काम करेगा *, क्योंकि शून्यता जांच तर्कसंगत प्रकार के तर्कों के लिए "सही काम करती है"। –

+0

क्या मैं गलत या शून्य प्रकार सभी structs हैं? मेरा मतलब है कि "शून्य प्रकार" के लिए कोई बाधा नहीं है लेकिन संरचना के लिए बाधा है। लेकिन मैंने अपना खुद का परीक्षण किया है और यदि, यदि आप कुछ जेनेरिक पैरामीटर के लिए टी: स्ट्रक्चर बाधा देते हैं, तो बाद में आप सामान्य तर्क के रूप में एक शून्य प्रकार का उपयोग नहीं कर सकते हैं। उदाहरण के लिए, एक्स इस बाधा के साथ काम नहीं करेगा। –

+0

जाहिर है यह इसलिए है क्योंकि int? Nullable और Nullable एक संदर्भ प्रकार है, लेकिन हो सकता है कि .NET devteam इस प्रकार के केस –

0

मैं इसे के रूप में Foo1 की वाक्य रचना के रूप में ज्यादा पसंद नहीं है, लेकिन यहाँ Foo3 है:

public class Foo3<T> 
    where T : struct 
{ 

    private T _value; 
    private T _nullValue; 

    public Foo3(T initValue) 
     : this(initValue, default(T)) 
    { 
    } 

    public Foo3(T initValue, T nullValue) 
    { 
     _value = initValue; 
     _nullValue = nullValue; 
    } 

    public T Value { get { return _value; } } 

    public bool IsNull 
    { 
     get 
     { 
      return object.Equals(_value, _nullValue); 
     } 
    } 

    public void Nullify() { _value = _nullValue; } 

} 

और फिर मेरी उपयोग हो जाता है:

Foo3<string> stringFoo = new Foo<string>("The answer is"); 
Foo3<int> intFoo = new Foo<int>(42, int.MinValue); 
stringFoo.Nullify(); 
intFoo.Nullify(); 
if (stringFoo.IsNull && intFoo.IsNull) 
    MessageBox.Show("Both are null); 

यह अभी भी त्रुटि प्रवण है क्योंकि Foo3 (और Foo2) की मान संपत्ति प्राप्त करना सरल नहीं है। Foo1 सबसे अच्छा था क्योंकि स्वचालित रूप से लपेटा गया मान शून्य समर्थन करेगा।

मुझे केवल ValueTypeFoo और ObjectFoo की आवश्यकता हो सकती है और दो छंदों से निपटने की आवश्यकता हो सकती है।

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^