2009-12-10 10 views
8

कहें कि मेरे पास एक विधि है जो स्ट्रिंग के रूप में एक int लेती है और अगर पार्स सफल हो जाती है या अन्यथा शून्य हो जाती है तो int को वापस कर देता है।जेनिक्स और नालीबल प्रकार

int? ParseValue(string intAsString) 
    { 
     int i; 
     if (int.TryParse(intAsString, out i)) 
      return i; 
     return null; 
    } 

इस विधि को फिर से लिखा जा सकता है ताकि यह न केवल int के साथ काम करता है, बल्कि लंबे समय तक ?, दशमलव? और डेटटाइम? ?

उत्तर

14

यह अजीब आप इसे का उल्लेख करना चाहिए, क्योंकि मैं कुछ के साथ चारों ओर खिलवाड़ किया गया था सिर्फ इस दूसरे दिन की तरह है:

using System; 
using System.Reflection; 

static class Example 
{ 
    public static Tuple<Boolean, T?> TryParse<T>(this String candidate) 
     where T : struct 
    { 
     T? value = null; 
     Boolean success = false; 

     var parser = ParsingBinder<T>.GetParser(); 

     try 
     { 
       value = parser(candidate); 
       success = true; 
     } 
     catch (FormatException) { } 

     return new Tuple<Boolean,T?>(success, value); 
    } 
} 

static class ParsingBinder<T> 
{ 
    static Func<String, T> parser; 

    public static Func<String, T> GetParser() 
    { 
     if (parser == null) 
       parser = getParser(); 

     return parser; 
    } 

    static Func<String, T> getParser() 
    { 
     MethodInfo methodInfo 
      = typeof(T).GetMethod(
        "Parse", new [] { typeof(String) }); 

     if (methodInfo == null) 
       throw new Exception(
         "Unable to retrieve a \"Parse\" method for type."); 

     return (Func<String, T>)Delegate 
     .CreateDelegate(typeof(Func<String, T>), methodInfo); 
    } 
} 

यह एक समान दृष्टिकोण है, लेकिन एक बेहतर TryParse विधि है कि एक Tuple<Boolean, T?> रिटर्न के रूप में विचार (इसके लिए .NET 4 की आवश्यकता है)। टुपल की पहली संपत्ति एक बूलियन वैल्यू है जो पार्सिंग प्रयास की सफलता या विफलता का संकेत देती है और दूसरी संपत्ति जेनेरिक टाइप तर्क के लिए टाइप की गई एक शून्य मूल्य है जो null होगी यदि पार्सिंग विफल हो जाती है और यदि पार्सिंग सफल होती है तो मान।

यह प्रतिबिंब का उपयोग कर सामान्य प्रकार तर्क से एक स्थिर Parse(String) विधि पुनः प्राप्त करने के द्वारा काम करता है और स्ट्रिंग है जो में मैं तुम्हें इस तरह सामान ऐसा करने की अनुमति के लिए एक विस्तार पद्धति के रूप में इसे बनाया पारित हो जाता है के लिए है कि विधि का आह्वान:।

var intValue = "1234".TryParse<Int32>(); 
var doubleValue = "1234".TryParse<Double>(); 

दुर्भाग्य से इस enums पर काम नहीं करेगा क्योंकि वे तो आप एक enum पार्स करने के लिए इस एक्सटेंशन का उपयोग नहीं कर सकता है पार्स विधि के लिए एक ही हस्ताक्षर की जरूरत नहीं है, लेकिन यह इस पर निर्भर हैक करने के लिए कठिन नहीं होगा enums के लिए एक विशेष मामला बनाओ।

इस दृष्टिकोण के बारे में अच्छी चीजों में से एक यह है कि प्रतिबिंब के माध्यम से Parse विधि को पुनर्प्राप्त करने की लागत केवल पहले उपयोग पर होती है क्योंकि सभी बाद के उपयोगों के लिए एक स्थिर प्रतिनिधि बनाया जाता है।


एक और बात - केवल एक चीज है कि इस दृष्टिकोण के बारे में भद्दा है कि वहाँ कोई भाषा एक्सटेंशन या वाक्यात्मक चीनी है कि इस के साथ काम करने के लिए आसान हो जाएगा है। मैं इस कोड के साथ प्राप्त करने की उम्मीद कर रहा था कम बीसीएल में मौजूद मानक TryParse विधियों का उपयोग करने का गुंजाइश तरीका था।

मैं व्यक्तिगत रूप से नहीं बल्कि बदसूरत इस पैटर्न को खोजने:

Int32 value; 
if (Int32.TryParse(someString, out value)) 
    // do something with value 

मुख्य रूप से, क्योंकि यह एक चर घोषणा समय से आगे और एक out पैरामीटर के उपयोग की आवश्यकता है। ऊपर मेरे दृष्टिकोण वास्तव में है कि ज्यादा बेहतर नहीं है:

var result = someString.TryParse<Int32>(); 
if (result.Item1) 
    // do something with result.Item2 

क्या वास्तव में एक सी # भाषा विस्तार है कि एक Tuple<Boolean, T?> के साथ काम करने कि हम आसानी से इस प्रकार के साथ काम करने की अनुमति होगी बनाया गया था देखने के लिए किया जाएगा शांत होगा, लेकिन मुझे लगता है कि मैं इस बारे में और अधिक महसूस कर रहा हूं कि यह वास्तव में संभव नहीं लगता है। बस करो: प्रश्न चिह्न का उपयोग करने का

+1

वास्तव में इस मान लिया जाये, काम करता है + 1: पी –

+0

'की TryParse' विफलता पर एक अपवाद फेंक नहीं है अस्तित्व के लिए प्राथमिक उद्देश्य को ध्यान में रखते, अपने" बेहतर दृष्टिकोण "अपने अस्तित्व के उद्देश्य पूर्ववत है: http: //www.codinghorror.com/blog/archives/000358.html –

+0

@ 280z28 - पर्याप्त मेला लेकिन अपवाद जो मैं फेंकता हूं वह अलग है। यह अपवाद तब फेंक दिया जाता है जब आप उस प्रकार को पार्स करने का प्रयास करते हैं जिसमें 'TryParse (स्ट्रिंग)' विधि नहीं होती है जो कभी भी तब नहीं होती जब आप सामान्य 'TryParse' विधि को कॉल करते हैं। यह अपवाद निस्संदेह डेवलपर द्वारा परीक्षण में पाया जाएगा और रनटाइम पर नहीं होगा, इसलिए यह बिल्कुल वही नहीं है जैसे अपवाद को पार्सिंग विफलता से मुखौटा किया जाएगा। –

3

इसके बजाय, आप स्पष्ट रूप से Nullable कीवर्ड का उपयोग कर सकते हैं: उदाहरण के लिए ,

int? के बराबर होती है Nullable<int>

इसलिए Nullable<T> ParseValue(string valueAsString करने के लिए अपने मूल डिजाइन स्विचिंग) चाल करना चाहिए इसके बाद सामान्य कार्यान्वयन।

2

यदि आप सी # 4.0 की प्रतीक्षा कर सकते हैं, तो आप dynamic कीवर्ड का उपयोग कर सकते हैं, जो इस तरह के परिदृश्य को हल करता है।

0

आपके द्वारा सूचीबद्ध सभी प्रकारों में TryParse नामक एक स्थिर विधि है। वे समान दिखते हैं, लेकिन वास्तव में हस्ताक्षर पूरी तरह से अलग हैं। वे एक समान 'पैटर्न' का पालन करते हैं, लेकिन यह संकलक द्वारा पता लगाने योग्य नहीं है। नहीं

public T? ParseValue<T>(string value) where T : struct 
    { 
     if (typeof(T) == typeof(int)) 
     { 
      int i; 
      if (int.TryParse(value, out i)) 
       return (T)(object)i; 
      return null; 
     } 
     if (typeof(T) == typeof(decimal)) 
     { 
      decimal d; 
      if (decimal.TryParse(value, out d)) 
       return (T)(object)d; 
      return null; 
     } 
     // other supported types... 
     throw new ArgumentException("Type not supported"); 
    } 

लेकिन, आप कर सकते हैं:

आप कुछ इस तरह से करने की कोशिश हो सकती है। कंपाइलर को टाइप करने के लिए कोई तरीका नहीं है (संकलन समय पर) प्रकार 'टी' को एक int (या किसी अन्य प्रकार) में कैसे परिवर्तित करें।

आप इस काम को करने के लिए डबल-कास्ट कर सकते हैं। (धन्यवाद, Dotson)

उपयोग:

enter code here:static T? TryParse<T>(string parse) 
     where T : struct 
    { 
     Type t=typeof(T); 
     if (t==typeof(int)) 
     { 
      int i; 
      if (int.TryParse(parse, out i)) 
       return (T)(object)i; 
      return null; 
      //Console.WriteLine(t.Name); 
     } 
     if (t == typeof(double)) 
     { 
      double i; 
      if (double.TryParse(parse, out i)) 
       return (T)(object)i; 
      return null; 
     } 
     //blabla, more logic like datetime and other data types 
     return null; 
    } 

और यह भी, आप:

 var mydecimal = ParseValue<decimal>("12.1"); 
     var myint = ParseValue<int>("-22"); 
     var badint = ParseValue<int>("Bad"); 
     // badint.HasValue == false 
+0

मुझे पहले किसी ऑब्जेक्ट पर कास्ट करें: (टी) (ऑब्जेक्ट) i –

0

असल में, आप अद्यतन कर सकते हैं क्या मैट कोड किया है और यह, और यहाँ कोड है इसे इस तरह प्रयोग करें: डबल? i = TryParse ("111.111"); int? ए = TryParse ("111");

3

एक्सटेंशन विधि को कार्यान्वित करना सबसे अच्छा है और आप गणनाओं को भी पार्स कर सकते हैं। इस तरह से आप इस तरह की एक Nullable <ForAnyValueType> प्राप्त कर सकते हैं: के रूप में हम एक Nullable वैसे भी लौट रहे हैं

public static T? Parse<T>(this string text) where T: struct 
    { 
     object o = null; 
     try { 
      var ttype = typeof(T); 
      if (ttype.IsEnum) 
      { 
       T n = default(T); 
       if (Enum.TryParse<T>(text, true, out n)) 
        return n; 
      } 
      else 
      o = Convert.ChangeType(text, ttype); 
     } 
     catch { } 

     if (o == null) 
      return new Nullable<T>(); 

     return new Nullable<T>((T)o); 
    } 
1

मैं वास्तव में, क्यों एंड्रयूज समाधान में टपल का उपयोग नहीं दिख रहा है जब तक, एक ही कर रही है की तरह लगता है दो बार बात मैंने TryParse का उपयोग करने के लिए अपना समाधान संपादित किया और तर्क के रूप में निर्दिष्ट एक शून्य या कुछ डिफ़ॉल्ट मान वापस करने की अनुमति दी।

/// <summary> 
    /// 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="aText"></param> 
    /// <returns></returns> 
    public static Nullable<T> TryParse<T>(this string aText) where T : struct { 
     T value; 
     if (ParsingBinder<T>.TryParse(aText, out value)) { 
      return value; 
     } 
     return null; 
    } 

    /// <summary> 
    /// 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="aText"></param> 
    /// <param name="aDefault"></param> 
    /// <returns></returns> 
    public static T TryParse<T>(this string aText, T aDefault) where T : struct { 
     T value; 
     if (!ParsingBinder<T>.TryParse(aText, out value)) { 
      value = aDefault; 
     } 
     return value; 
    } 

    /// <summary> 
    /// 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    static class ParsingBinder<T> where T : struct { 

     /// <summary> 
     /// 
     /// </summary> 
     /// <typeparam name="T"></typeparam> 
     /// <param name="aText"></param> 
     /// <param name="aOutput"></param> 
     /// <returns></returns> 
     public delegate bool Delegate_TryParse<T>(string aText, out T aOutput) where T : struct; 

     /// <summary> 
     /// 
     /// </summary> 
     static Delegate_TryParse<T> methodTryParse; 

     /// <summary> 
     /// 
     /// </summary> 
     /// <returns></returns> 
     public static Delegate_TryParse<T> TryParse { 
      get { 
       if (methodTryParse == null) { 
        methodTryParse = GetParserMethod(); 
       } 
       return methodTryParse; 
      } 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <returns></returns> 
     static Delegate_TryParse<T> GetParserMethod() { 
      var typeT = typeof(T); 
      var paramTypes = new Type[] { typeof(string), typeT.MakeByRefType() }; 
      var methodInfo = typeT.GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, null, paramTypes, null); 
      if (methodInfo == null) { 
       var message = String.Format("Unable to retrieve a 'TryParse' method for type '{0}'.", typeT.Name); 
       throw new Exception(message); 
      } 
      return (Delegate_TryParse<T>) Delegate.CreateDelegate(typeof(Delegate_TryParse<T>), methodInfo); 
     } 
    } 
संबंधित मुद्दे