2009-01-24 21 views
7

मेरे विशेष समस्या:मैं किसी प्रकार से TryParse विधि से कैसे प्राप्त करूं?

मैं एक स्ट्रिंग जो एक विन्यास कक्षा में एक aribitrary प्रकार निर्दिष्ट करता है

Config.numberType = "System.Foo";

जहां Foo तरह Decimal या Double

मैं Type.GetType(Config.numberType) का प्रयोग कर एक प्रकार वापस जाने के लिए है संबंधित प्रकार।

System.Foo.TryParse() का उपयोग करने में सक्षम होने के लिए मैं उस प्रकार से कैसे प्राप्त करूं?

कुछ आगे संबंधित प्रश्नों

  • TryParse()System.Foo.TryParse() के साथ-साथ foo.TryParse() से पहुँचा जा सकता। क्या इसका मतलब है foo सी # में किसी प्रकार का वर्ग है? यह मेरे लिए अजीब लगता है कि int, double आदि वास्तव में केवल संशोधक कीवर्ड नहीं हैं।
  • आप इन परिस्थितियों में चर कैसे घोषित कर सकते हैं? - var नहीं सार्वभौमिक प्रयोग करने योग्य ऐसा लगता है यानी केवल स्थानीय दायरे में आदि
+0

'var' वर्तमान में एक विधि के दायरे में ही उपलब्ध है। विवरण के लिए http://stackoverflow.com/q/4461597/1086351 देखें – fcrick

उत्तर

20

के रूप में कई ने कहा है - वहाँ एक सीधा रास्ता नहीं है। मैं उम्मीद एक बंद करें विकल्प TypeConverter है:

Type type = typeof(double); 
    string text = "123.45"; 

    object value = TypeDescriptor.GetConverter(type) 
     .ConvertFromInvariantString(text); 

बेशक, आप अपवाद को संभालने के लिए try/catch पड़ सकता है। ऐसे जीवन है।

+1

ध्यान दें कि अधिकतर विकल्पों के विपरीत, यह एक्स्टेंसिबल और स्व-रखरखाव है; कई मानक और bespoke प्रकार कन्वर्टर्स जुड़े हैं। –

+0

एक ही समस्या थी और इस विधि को सफलतापूर्वक इस्तेमाल किया। धन्यवाद। –

7

मैं कैसे उस प्रकार से का उपयोग करने में सक्षम होने के लिए मिलता है, System.Foo.TryParse()?

आप प्रतिबिंब का उपयोग को देखने के लिए और उसके बाद स्थिर TryParse() विधि को लागू करने की आवश्यकता होगी। सभी प्रकार इस विधि को लागू नहीं करते हैं - इसलिए आपको यह तय करना होगा कि यह गायब होने पर इसे कैसे संभालना है। स्ट्रिंग को मनमाना प्रकार में बदलने के लिए आप System.Convert का भी उपयोग कर सकते हैं, मानते हैं कि स्ट्रिंग वास्तव में उस प्रकार के और के मान का मान्य प्रतिनिधित्व है, इसके लिए एक रूपांतरण लागू किया गया है।

TryParse() System.Foo.TryParse (से पहुँचा जा सकता) और साथ ही foo.TryParse()। क्या इसका मतलब है कि foo सी # में किसी प्रकार का वर्ग है?

int, double, आदि aliases हैं System.Int32, System.Double, आदि के लिए - वे सी # भाषा है, जो उन्हें बिना असुविधाजनक वर्बोज़ होगा का हिस्सा हैं।

आप इन परिस्थितियों में के तहत चर कैसे घोषित कर सकते हैं?

संकलन समय पर प्रकार जानने के बिना, आप घोषित करने और के रूप में object/System.Object अपने डेटा के साथ काम करने को मजबूर हो जाएगा। सी # 4.0 वास्तविक गतिशील प्रकारों को पेश करेगा जो आपके लिए कुछ कठिन प्रतिबिंब कार्य का ख्याल रखेंगे, लेकिन अभी के लिए आप इसे हाथ से कर रहे हैं। ध्यान दें कि यदि एक विधि with a parametrized type argument and return, या TryParse() में linked to by Sebastian Sedlak जैसी तकनीक का उपयोग करके, आप आसानी से क्लाइंट कोड लिखने की क्षमता प्राप्त कर सकते हैं जो स्थिर प्रकारों के साथ काम करता है ...जब तक वे मिलान करते हैं या उन प्रकारों से परिवर्तित किए जा सकते हैं जिन्हें आप पार्स कर रहे हैं।

+0

TryParse स्थिर होने के अलावा; 'गतिशील' उदाहरणों पर लागू होता है। –

+0

@Marc: मेरा मतलब था कि अपने अंतिम प्रश्न के उत्तर के रूप में (जब आप संकलन-समय पर प्रकार को नहीं जानते हैं तो आप चर के लिए किस प्रकार का उपयोग कर सकते हैं)। लेकिन हाँ, 'गतिशील' अपनी पहली समस्या में मदद करने के लिए बहुत कम करेगा। सेबस्टियन कोड को पूरा करने के लिए एक सभ्य तरीका की तरह दिखता है। – Shog9

5

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

नोट: मार्क ग्रेवेल द्वारा उत्तर शायद सबसे संक्षिप्त है यदि आप सिर्फ प्रकार के पार्स किए गए मान को चाहते हैं। नीचे दिया गया जवाब आपको दिखाता है कि विधि को कैसे प्राप्त करें (यानी, MethodInfo ऑब्जेक्ट और इसे कैसे आमंत्रित करें)।

निम्नलिखित काम करना चाहिए, कम से कम प्रकार है कि bool TryParse (स्ट्रिंग, टी मूल्य) सार्वजनिक स्थैतिक लागू के लिए:

public static class Parsing 
{ 
    static MethodInfo findTryParseMethod(Type type) 
    { 
     //find member of type with signature 'static public bool TryParse(string, out T)' 
     BindingFlags access = BindingFlags.Static | BindingFlags.Public; 
     MemberInfo[] candidates = type.FindMembers(
      MemberTypes.Method, 
      access, 
      delegate(MemberInfo m, object o_ignored) 
      { 
       MethodInfo method = (MethodInfo)m; 
       if (method.Name != "TryParse") return false; 
       if (method.ReturnParameter.ParameterType != typeof(bool)) return false; 
       ParameterInfo[] parms = method.GetParameters(); 
       if (parms.Length != 2) return false; 
       if (parms[0].ParameterType != typeof(string)) return false; 
       if (parms[1].ParameterType != type.MakeByRefType()) return false; 
       if (!parms[1].IsOut) return false; 

       return true; 

      }, null); 

     if (candidates.Length > 1) 
     { 
      //change this to your favorite exception or use an assertion 
      throw new System.Exception(String.Format(
       "Found more than one method with signature 'public static bool TryParse(string, out {0})' in type {0}.", 
       type)); 
     } 
     if (candidates.Length == 0) 
     { 
      //This type does not contain a TryParse method - replace this by your error handling of choice 
      throw new System.Exception(String.Format(
       "Found no method with signature 'public static bool TryParse(string, out {0})' in type {0}.", 
       type)); 
     } 
     return (MethodInfo)candidates[0]; 
    } 

    public static bool TryParse(Type t, string s, out object val) 
    { 
     MethodInfo method = findTryParseMethod(t); //can also cache 'method' in a Dictionary<Type, MethodInfo> if desired 
     object[] oArgs = new object[] { s, null }; 
     bool bRes = (bool)method.Invoke(null, oArgs); 
     val = oArgs[1]; 
     return bRes; 
    } 

    //if you want to use TryParse in a generic syntax: 
    public static bool TryParseGeneric<T>(string s, out T val) 
    { 
     object oVal; 
     bool bRes = TryParse(typeof(T), s, out oVal); 
     val = (T)oVal; 
     return bRes; 
    } 
} 

उपयोग निम्न परीक्षण कोड:

 public bool test() 
    { 
     try 
     { 
      object oVal; 
      bool b = Parsing.TryParse(typeof(int), "123", out oVal); 
      if (!b) return false; 
      int x = (int)oVal; 
      if (x!= 123) return false; 
     } 
     catch (System.Exception) 
     { 
      return false; 
     } 

     try 
     { 
      int x; 
      bool b = Parsing.TryParseGeneric<int>("123", out x); 
      if (!b) return false; 
      if (x != 123) return false; 
     } 
     catch (System.Exception) 
     { 
      return false; 
     } 


     try 
     { 
      object oVal; 
      bool b = Parsing.TryParse(typeof(string), "123", out oVal); 
      //should throw an exception (//no method String.TryParse(string s, out string val) 
      return false; 
     } 
     catch (System.Exception) 
     { 
      //should throw an exception 
     } 

     return true; 
    } 
} 

और में इस का उपयोग अपने मामले:

//input: string s, Config 
Type tNum = Type.GetType(Config.numberType);  
object oVal; 
bool ok = Parsing.TryParse(tNum, s, out oVal); 
//oVal is now of type tNum and its value is properly defined if ok == true 

वर के उपयोग के बारे में: आप क्या वर करता है की एक गलत धारणा है हो सकता है: यह है एक "संस्करण" प्रकार नहीं है (टाइप ऑब्जेक्ट पहले से ही इसके लिए उपयोग किया जाता है) लेकिन इस प्रकार के लिए घोषणा सिंटैक्स को असाइनमेंट के दाएं तरफ ले जाता है। निम्नलिखित घोषणाओं के बराबर हैं:

var anon = new { Name = "abc", X = 123 }; 
+0

इसे कनवर्ट करने से पहले प्री-पास के रूप में जोड़ा गया। चेंज टाइप, मूल रूप से केवल अपवादों को काटने के लिए - बहुत अच्छा काम करता है! – fcrick

1

और एक और good link to this problem:

var i = 1; //the compiler infers the type from the assignment, type of i is int. 
int i = 1; //type of i is int via declaration 

वर का प्राथमिक उपयोग गुमनाम प्रकार बनाने की अनुमति है। उस साइट पर स्रोत कोड बहुत खराब स्वरूपित है, इसलिए मैंने इसे यहां रखा है। उम्मीद है कि लेखक मुझ पर मुकदमा नहीं करता है।

public static T Parse<T>(string s) 
{ 
    Type t = typeof(T); 
    // Attempt to execute the Parse method on the type if it exists. 
    MethodInfo parse = t.GetMethod("Parse", new Type[] { typeof(string) }); 

    if (parse != null) 
    { 
     try 
     { 
      return (T)parse.Invoke(null, new object[] { s }); 
     } 
     catch (Exception ex) 
     { 
      throw ex.InnerException; 
     } 
    } 
    else 
    { 
     throw new MethodAccessException(String.Format("The Parse method does not exist for type {0}.", t.Name)); 
    } 
} 

public static bool TryParse<T>(string s, out T result) 
{ 
    return TryParse<T>(s, false, out result); 
} 

public static bool TryParse<T>(string s, bool throwException, out T result) 
{ 
    result = default(T); 
    Type t = typeof(T); 
    T type = default(T); 

    // Look for the TryParse method on the type. 
    MethodInfo tryParse = t.GetMethod("TryParse", new Type[] { typeof(string), Type.GetType(t.FullName + "&") }); 
    if (tryParse != null) 
    { 
     // Try parse exists. Call it. 
     Object[] ps = new Object[2]; 
     ps[0] = s; 

     bool isSuccess = (bool)tryParse.Invoke(type, ps); 

     if (isSuccess) 
      result = (T)ps[1]; 

     return isSuccess; 
    } 
    else 
    { 
     // TryParse does not exist. Look for a Parse method. 
     try 
     { 
      result = Parse<T>(s); 
      return true; 
     } 
     catch 
     { 
      if (throwException) 
       throw; 

      return false; 
     } 
    } 
} 
संबंधित मुद्दे