2012-01-05 22 views
28

मैं IENumerable पर एक एक्सटेंशन विधि लिखने की कोशिश कर रहा हूं जो केवल मूल्य प्रकारों और तारों पर लागू होगी।सी # सामान्य प्रकारों और मूल्यों को शामिल करने के लिए सामान्य बाधाएं

public static string MyMethod<T>(this IEnumerable<T> source) where T : struct, string 

हालांकि 'स्ट्रिंग' एक वैध बाधा नहीं है क्योंकि यह एक सीलबंद वर्ग है।

क्या ऐसा करने का कोई तरीका है?

संपादित करें:

क्या मैं वास्तव में क्या करने के लिए कोशिश कर रहा हूँ एक गतिशील निर्माण एसक्यूएल में एक "में" खंड के लिए मूल्यों की एक सूची तैयार है।

मैं जैसे कि निम्न कोड के उदाहरण के बहुत सारे है कि मैं साफ करने के लिए करना चाहते हैं:

sb.AppendLine(string.Format("AND value IN ({0})", string.Join(",", Values.Select(x => x.ToSQL()).ToArray()))); 

कहाँ ToSQL() SqlInjection को संभालने के लिए कोड है।

+0

आपके कार्यान्वयन के लिए, मूल्य-प्रकार और तार स्वीकार्य बनाता है जहां अन्य नहीं हैं? –

उत्तर

22

नहीं, आप नहीं कर सकते। जेनेरिक बाधाएं हमेशा "और" होती हैं, यदि आप देखते हैं कि मेरा क्या मतलब है (यानी सभी बाधाओं को सताया जाना चाहिए), इसलिए यदि आप कुछ असीमित वर्ग का उपयोग करने की कोशिश कर रहे थे, तो भी यह असफल हो जाएगा।

आप ऐसा क्यों करना चाहते हैं? शायद एक और दृष्टिकोण है जो बेहतर काम करेगा।

+0

धन्यवाद। सबसे अच्छा विकल्प क्या होगा? दो अलग-अलग तरीकों? –

+0

@Poz: यह देखते हुए कि मैं एसक्यूएल में मूल्यों को प्रारूपित करने के लिए प्रारूपित नहीं करता हूं, मैं इसके बजाय पैरामीटरयुक्त प्रश्नों का उपयोग करने के लिए रिफैक्टरिंग का सुझाव दूंगा ... –

+0

हमने शुरुआत में उस मार्ग पर जाने की कोशिश की। हालांकि SQL सर्वर में पैरामीटर के रूप में गुजरने वाली सूचियों के साथ समस्याएं, और किसी चीज़ पर विभाजित करने की आवश्यकता जो मूल्यों के भीतर वैध पाठ हो सकती है, हमें अपना दृष्टिकोण बदल देता है। एसक्यूएल को गतिशील रूप से भी बनाया गया है, सशर्त जुड़ने आदि के साथ, जिसे हमने महसूस किया है कि संग्रहीत प्रक्रिया के बजाय कोड में बेहतर किया जाएगा। यह एक प्रश्न है जिसमें इस पर फेंकने वाले पैरामीटर के कई क्रमपरिवर्तन हो सकते हैं, यही कारण है कि हम इसे स्थिर एसक्यूएल नहीं बना सकते हैं। –

32

आप में 2 अलग तरीकों परिभाषित करना होगा:

public static string MyMethod<T>(this IEnumerable<T> source) where T : struct 
public static string MyMethod(this IEnumerable<string> source) 
+1

आपके पास एक तीसरी, निजी विधि भी हो सकती है जो इन दोनों विधियों को चीजों को थोड़ा डीआरआईआर-एर रखने के लिए बुलाती है। एक ही प्रश्न के लिए [यह उत्तर] देखें (http://stackoverflow.com/a/4109547/957950)। – brichins

44

शायद आप IConvertible प्रकार के लिए प्रतिबंधित कर सकता है? सभी प्रणाली पुरातन है कि इन इंटरफेस तरीकों का उपयोग कर भी इंटरफ़ेस को लागू परिवर्तित किया जा सकता है, तो इस प्रतिबंध को टी की आवश्यकता होगी निम्न में से एक होने के लिए:

  • बूलियन
  • बाइट
  • चार
  • दिनांक समय
  • दशमलव
  • डबल
  • इंट (16, 32 और 64-बिट)
  • SByte
  • एकल (नाव)
  • स्ट्रिंग
  • uint (16, 32 और 64-बिट)

आप एक IConvertible है, तो संभावना है कि बहुत अच्छा यह इन प्रकार में से एक है, के रूप में कर रहे हैं IConvertible इंटरफेस इस तरह के दर्द को लागू करने के लिए है कि यह शायद ही कभी तीसरे पक्ष के प्रकार के लिए किया जाता है।

मुख्य दोष यह है कि वास्तव में टी को इन प्रकारों में से किसी एक के उदाहरण में परिवर्तित करने के बिना, आपकी सभी विधि पता चलेगी कि ऑब्जेक्ट और आईकोनवर्टेबल विधियों या ऑब्जेक्ट्स या आईकोनवर्टिबल लेने वाले तरीकों को कैसे कॉल किया जाए। यदि आपको कुछ और चाहिए (जैसे कि जोड़ने और/या उपयोग करने की क्षमता +), मुझे लगता है कि बस दो विधियों को स्थापित करना, स्ट्रक्चर प्रकारों के लिए एक सामान्य और दूसरा दृढ़ता से स्ट्रिंग्स टाइप करना, समग्र रूप से सबसे अच्छा शर्त होगा।

+1

महान विचार! मैंने इसके बारे में सोचा नहीं था। –

8

मैंने एक हैक-समाधान का उपयोग किया: इंटरफ़ेस। इंटरफेस में निर्मित मूल्य प्रकार और स्ट्रिंग प्रकार लागू कर दिया है देखें:

struct Int32 : IComparable, IFormattable, IConvertible, IComparable<int>, IEquatable<int> 

class String : IComparable, ICloneable, IConvertible, IComparable<string>, IEnumerable<char>, IEnumerable, IEquatable<string> 

struct Boolean : IComparable, IConvertible, IComparable<bool>, IEquatable<bool> 

struct DateTime : IComparable, IFormattable, IConvertible, ISerializable, IComparable<DateTime>, IEquatable<DateTime> 

struct UInt64 : IComparable, IFormattable, IConvertible, IComparable<ulong>, IEquatable<ulong> 

struct Single : IComparable, IFormattable, IConvertible, IComparable<float>, IEquatable<float> 

struct Byte : IComparable, IFormattable, IConvertible, IComparable<byte>, IEquatable<byte> 

struct Char : IComparable, IConvertible, IComparable<char>, IEquatable<char> 

struct Decimal : IFormattable, IComparable, IConvertible, IComparable<decimal>, IEquatable<decimal> 

आप बाधाओं के लिए IComparable,IConvertible,IEquatable<T> उपयोग कर सकते हैं। इस तरह:

public static void SetValue<T>(T value) where T : IComparable, IConvertible, IEquatable<T> 
    { 
     //TODO: 
    } 

या आप बाधाओं के बिना डेटा समय की जाँच करने के प्रकार कोड का उपयोग कर सकते हैं।

public static void SetValue<T>(T value) 
    { 
     switch (Type.GetTypeCode(typeof(T))) 
     { 
      #region These types are not what u want, comment them to throw ArgumentOutOfRangeException 

      case TypeCode.Empty: 
       break; 
      case TypeCode.Object: 
       break; 
      case TypeCode.DBNull: 

       #endregion 

       break; 
      case TypeCode.Boolean: 
       break; 
      case TypeCode.Char: 
       break; 
      case TypeCode.SByte: 
       break; 
      case TypeCode.Byte: 
       break; 
      case TypeCode.Int16: 
       break; 
      case TypeCode.UInt16: 
       break; 
      case TypeCode.Int32: 
       break; 
      case TypeCode.UInt32: 
       break; 
      case TypeCode.Int64: 
       break; 
      case TypeCode.UInt64: 
       break; 
      case TypeCode.Single: 
       break; 
      case TypeCode.Double: 
       break; 
      case TypeCode.Decimal: 
       break; 
      case TypeCode.DateTime: 
       break; 
      case TypeCode.String: 
       break; 
      default: 
       throw new ArgumentOutOfRangeException(); 
     } 
    } 

याद रखें कि ऑब्जेक्ट प्रकार का उपयोग न करें लेकिन पैरामीटर प्रकार के लिए सामान्य प्रकार का उपयोग न करें। अन्यथा जब आप शून्य शून्य हो तो कोडलाइन Type.GetTypeCode(value.GetType()) पर आपको एक पूर्ण निष्कासन मिल सकता है।

0

कक्षा का उपयोग होने पर टाइप पैरामीटर की जांच करने के लिए आप एक स्थिर कंस्ट्रक्टर का उपयोग कर सकते हैं।

class Gen<T> { 
    static Gen() { 
     if (!typeof(T).IsValueType && typeof(T) != typeof(String)) 
     { 
      throw new ArgumentException("T must be a value type or System.String."); 
     } 
    } 
} 
+2

यह समय संकलित करने में आपकी सहायता नहीं करता है, जो वास्तव में जेनिक्स के लिए उपयोग किया जाना चाहिए। कन्स्ट्रक्टर में अपवाद फेंकना भी बहुत कठोर है, खासतौर पर एक स्थिर कन्स्ट्रक्टर में - उपभोक्ताओं को रनटाइम पर एक अनुपयोगी "TypeInitializerException" मिल जाएगा और उन्हें पता नहीं है कि क्यों। –