2012-11-12 20 views
9

पर विचार करें निम्नलिखित सामान्य वर्ग:जेनेरिक प्रकार पैरामीटर की कमी

public class Custom<T> where T : string 
{ 
} 

यह निम्न त्रुटि पैदा करता है:

'string' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter.

वहाँ एक और तरीका है जो प्रकार मेरी सामान्य वर्ग का उपयोग कर सकते विवश करने के लिए है ?

इसके अलावा, क्या मैं कई प्रकार से बाध्य कर सकता हूं?

ईजी।

T can only be string, int or byte

+0

सबसे अच्छा आप इन स्थितियों के लिए वास्तव में कर सकते हैं एक रैपर वर्ग बनाते हैं, या कुछ और सामान्य (ऑब्जेक्ट) लेते हैं और कन्स्ट्रक्टर में टाइप-चेकिंग करते हैं। क्या यह सुंदर है? नहीं। क्या यह काम करेगा? हाँ। – sybkar

+0

@ सब्बर, क्या आपका मतलब मेरे उत्तर में है? – series0ne

उत्तर

16
public class Custom<T> where T : string 

, अनुमति दी है नहीं क्योंकि केवलT को पूरा करती है कि वह यह है कि: string (stringsealed है) - यह नहीं बल्कि एक सामान्य रूप में व्यर्थ हो जाता है।

Also, can I constrain to multiple types?

नहीं - जब तक आप उस के बजाय एक बाधा में प्रतिबिंब के माध्यम से कार्यावधि में (स्थिर निर्माता एक ही रास्ता है कि ऐसा करने के लिए है - एक अपवाद फेंक अगर गलत तरीके से इस्तेमाल किया) कर

T can only be string, int or byte

आप हो सकता हैIEquatable<T> जैसे कुछ का उपयोग करें, लेकिन यह जितना चाहें उतना प्रतिबंधित नहीं करता है, इसलिए आखिरकार: नहीं।

कुछ आप सकता है करना है एक ओवरलोड कारखाने के माध्यम से इसे उपयोग:

public abstract class Custom 
{ 
    public static Custom Create(int value) 
    { return new CustomImpl<int>(value); } 
    public static Custom Create(byte value) 
    { return new CustomImpl<byte>(value); } 
    public static Custom Create(string value) 
    { return new CustomImpl<string>(value); } 
    private class CustomImpl<T> : Custom 
    { 
     public CustomImpl(T val) { /*...*/ } 
    } 
} 
+0

आपके उत्तर के लिए धन्यवाद ... मेरे पास थोड़ा सा खेल था। यदि आपके पास एक मिनट है और देखें कि आप क्या सोचते हैं तो कृपया मेरे उत्तर पर एक नज़र डालें। किसी भी रचनात्मक आलोचना की सराहना की है! :-) – series0ne

+0

"पब्लिक क्लास कस्टम जहां टी: स्ट्रिंग ... की अनुमति नहीं है, क्योंकि केवल टी जो मिलती है वह है: स्ट्रिंग (स्ट्रिंग सील कर दी गई है) - इसे सामान्य के रूप में व्यर्थ बनाते हैं।" - सहमत है, अपने आप पर स्ट्रिंग व्यर्थ है, लेकिन कहें कि मैं स्ट्रिंग, स्ट्रिंगबिल्डर और सिक्योरस्टिंग को बाध्य करना चाहता हूं। यह अधिक उपयोगी होगा, लेकिन फिर भी अवैध becuase स्ट्रिंग को सील कर दिया गया है :-( – series0ne

+0

@activwerx जो जेनेरिक द्वारा समर्थित कुछ नहीं है। –

2

मेरे अनुभव से मैं कहूँगा कि मैं समझता हूँ कि तुम क्यों है, string और int चाहते हैं ... क्योंकि एक की जेनेरिक बेस क्लास आईडी प्रकार स्ट्रिंग या int

लेकिन यह निश्चित रूप से है, यह संभव नहीं है। इस MSDN वर्णन कहते हैं: त्रुटि: http://msdn.microsoft.com/en-us/library/d5x73970%28v=vs.80%29.aspx

हम struct (पूर्णांक की तरह ValueType) एक constraing class (स्ट्रिंग की तरह संदर्भ वस्तु) या तो मिश्रण स्ट्रिंग और पूर्णांक संभव नहीं होगा

नोट हो सकता है स्ट्रिंग के लिए, क्योंकि स्ट्रिंग बंद है, मतलब तो यह सामान्य रूप में होने की ज़रूरत नहीं है - स्ट्रिंग आईडी क्या हम

1

जरूरत है यहाँ जवाब की समीक्षा करने, और अपने आप को चारों ओर एक छोटे से खेलने के बाद है, मैं ऊपर आ गए हैं निम्नलिखित कार्यान्वयन के साथ, जो जांचता है समय संकलित करने के बजाए रनटाइम पर बाधाएं।

// This example takes 3 parameters... 
public class GenericConstraint<T1, T2, T3> 
{ 
    public GenericConstraint(Type type) 
    { 
     if (!(type is T1) || !(type is T2) || !(type is T3)) 
     { 
      throw new Exception("This is not a supported type"); 
     } 
    } 
} 

अब मैं इसे अपने कस्टम वर्ग से प्राप्त करता हूं ...

Custom<long> item = new Custom<long>(); 

यह नहीं करता है:

public class Custom<T> : GenericConstraint<string, int, byte> 
{ 
    public Custom() : base(typeof(T)) 
    { 
    } 
} 

यह अब एक त्रुटि फेंकता है!

Custom<byte> item2 = new Custom<byte>(); 

जैसा कि मार्क ग्रेवेल ने कहा है, यह विरासत या जेनेरिक का अच्छा उपयोग नहीं है। जेनेरिककोनस्ट्रेन को विरासत में रखते हुए, इस तर्कसंगत रूप से सोचते हुए, यह केवल विरासत को सीमित कर रहा है, और टाइप पदानुक्रम का सही उपयोग नहीं कर रहा है। जेनेरिक के उपयोग के संदर्भ में, यह वास्तव में सुंदर व्यर्थ है!

इसलिए मेरे पास एक और समाधान है जो रनटाइम पर प्रकारों को बाधित करने के लिए एक सहायक विधि के रूप में कार्य करता है। यह वस्तु को विरासत से मुक्त करता है और इसलिए प्रकार पदानुक्रम पर कोई प्रभाव नहीं पड़ता है।

public static void ConstrainParameterType(Type parameterType, GenericConstraint constraintType, params Type[] allowedTypes) 
     { 
      if (constraintType == GenericConstraint.ExactType) 
      { 
       if (!allowedTypes.Contains<Type>(parameterType)) 
       { 
        throw new Exception("A runtime constraint disallows use of type " + parameterType.Name + " with this parameter."); 
       } 
      } 
      else 
      { 
       foreach (Type constraint in allowedTypes) 
       { 
        if (!constraint.IsAssignableFrom(parameterType)) 
        { 
         throw new Exception("A runtime constraint disallows use of type " + parameterType.Name + " with this parameter."); 
        } 
       } 
      } 
     } 

public enum GenericConstraint 
    { 
     /// <summary> 
     /// The type must be exact. 
     /// </summary> 
     ExactType, 

     /// <summary> 
     /// The type must be assignable. 
     /// </summary> 
     AssignableType 
    } 

यह अब सामान्य वस्तुओं पर कई प्रकार की कमी की अनुमति देता है, यहां तक ​​कि जहां प्रकार सील कर रहे हैं आदि

"public class Custom where T : string ... is not allowed, because the only T that meets that is: string (string is sealed) - making it rather pointless as a generic."

हाँ, यह व्यर्थ है, लेकिन कुछ परिस्थितियों में, आप के लिए एक वस्तु विवश करना चाह सकते हैं उदाहरण के लिए अनुमति दें; स्ट्रिंग, स्ट्रिंगबिल्डर और सिक्योरस्टिंग। हालांकि यह संकलन समय बाधा प्रदान नहीं करता है, यह रनटाइम बाधा प्रदान करता है, और कुछ लचीलापन किस प्रकार बाधा में उपयोग किया जा सकता है।

+4

वास्तव में एक महान नहीं है जेनेरिक * या * विरासत का उपयोग, आईएमओ .... –

+0

लेकिन ऐसे समय पर कोई कामकाज नहीं होता है जब हमारे विकल्प सी # और .NET के डिजाइन सिद्धांतों से बाधित होते हैं। – nawfal

+0

@nawfal, क्या आप विस्तृत कर सकते हैं? – series0ne

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