2009-07-09 14 views
17

मेरे पास निम्न परिदृश्य है जहां मैं स्ट्रिंग और सामान्य प्रकार में पास करना चाहता हूं:मैं TryParse() के सामान्य संस्करण में किसी विशिष्ट प्रकार में कैसे परिवर्तित कर सकता हूं?

public class Worker { 
    public void DoSomeWork<T>(string value) 
     where T : struct, IComparable<T>, IEquatable<T> { ... } 
} 

जिस तरह से मुझे स्ट्रिंग मान को अपने T मान में परिवर्तित करने की आवश्यकता है। लेकिन मैं सीधे कन्वर्ट नहीं करना चाहता क्योंकि मुझे कुछ तर्क करने की ज़रूरत है यदि स्ट्रिंग को T प्रकार में परिवर्तित नहीं किया जा सकता है।

मैं सोच रहा था कि मैं Convert.ChangeType() का उपयोग करने का प्रयास कर सकता हूं लेकिन इसमें समस्या है कि अगर यह परिवर्तित नहीं होता है तो यह एक अपवाद फेंक देगा और मैं DoSomeWork() विधि को अक्सर चलाने के लिए पर्याप्त प्रयास नहीं करूँगा यह निर्धारित करने के लिए कि रूपांतरण मान्य है या नहीं।

तो यह मुझे सोचने लगा, मुझे पता है कि मैं संख्यात्मक प्रकारों के साथ काम कर रहा हूं, इसलिए टी निम्न में से कोई भी होगा: int, uint, short, ushort, long, ulong, byte, sbyte, decimal, float, double। यह जानकर मैंने सोचा कि इस तथ्य के साथ काम करने के लिए एक तेज़ समाधान के साथ आना संभव हो सकता है कि मुझे पता है कि मैं संख्यात्मक प्रकारों का उपयोग करूँगा (ध्यान दें कि T एक संख्यात्मक प्रकार नहीं है जिसे मैंने अपवाद फेंक दिया है) ...

public class NumericWorker { 
    public void DoSomeWork<T>(string value) 
     where T : struct, IComparable<T>, IEquatable<T> 
    { 
     ParseDelegate<T> tryConverter = 
      SafeConvert.RetreiveNumericTryParseDelegate<T>(); 
     ... 
    } 
} 


public class SafeConvert 
{ 
    public delegate bool ParseDelegate<T>(string value, out T result); 

    public static ParseDelegate<T> RetreiveNumericTryParseDelegate<T>() 
     where T : struct, IComparable<T>, IEquatable<T> 
    { 
     ParseDelegate<T> tryParseDelegate = null; 

     if (typeof(T) == typeof(int)) 
     { 
      tryParseDelegate = (string v, out T t) => 
       { 
       int typedValue; 
       bool result = int.TryParse(v, out typedValue); 
       t = result ? (T)typedValue : default(T); 
       //(T)Convert.ChangeType(typedValue, typeof(T)) : default(T); 
       return result; 
       }; 
     } 
     else if (typeof(T) == typeof(uint)) { ... } 
     else if (typeof(T) == typeof(short)) { ... } 
     else if (typeof(T) == typeof(ushort)) { ... } 
     else if (typeof(T) == typeof(long)) { ... } 
     else if (typeof(T) == typeof(ulong)) { ... } 
     else if (typeof(T) == typeof(byte)) { ... } 
     else if (typeof(T) == typeof(sbyte)) { ... } 
     else if (typeof(T) == typeof(decimal)) { ... } 
     else if (typeof(T) == typeof(float)) { ... } 
     else if (typeof(T) == typeof(double)) { ... } 

     return tryParseDelegate; 
    } 
} 

लेकिन उपर्युक्त समस्या है कि मैं t = result ? (T)typedValue : default(T); नहीं लिख सकता क्योंकि typedValue से T का कास्टिंग मुद्दों का कारण बनता है और एकमात्र तरीका मैं इसके आसपास पाने में सक्षम हूं, इस प्रकार (T)Convert.ChangeType(typedValue, typeof(T)) लिख रहा है। लेकिन अगर मैं ऐसा करता हूं तो मैं बस एक और कन्वर्ट कर रहा हूं।

इसलिए मैं सोच रहा था कि अगर कोई जानता है कि मैं इस समस्या को कैसे ठीक कर सकता हूं (यदि आपको लगता है कि ChangeType() करना कोई समस्या है) या यदि कोई बेहतर समाधान है तो मैंने पूरी तरह से विचार नहीं किया है।

उत्तर

37

टी = परिणाम? (टी) टाइप किया गया वैल्यू: डिफ़ॉल्ट (टी);

प्रयास करें:

t = result ? (T)(object)typedValue : default(T); 

हाँ, जेनरिक थोड़े समय पर कष्टप्रद हो सकता है।

एफडब्ल्यूआईडब्ल्यू, मैं a much simpler wrapperConvert.ChangeType() का उपयोग करता हूं जो खाली तारों के लिए पूर्व-जांच करता है। जब तक आप इसे अन-चेक किए गए उपयोगकर्ता इनपुट के लिए उपयोग नहीं कर रहे हैं, तो शायद यह पर्याप्त होगा।

+0

क्या मैं के लिए उपयोगकर्ता इनपुट को मान्य है यह उपयोग कर रहा हूँ ... :(तो thats क्यों मैं changetype पकड़ का उपयोग करें और प्रयास करने के लिए/क्योंकि नहीं करना चाहता था कौन जानता है कि उपयोगकर्ता क्या टाइप करेगा ... –

+0

हे, ठीक है :-) एफडब्ल्यूआईडब्ल्यू, मैं 'चेंज टाइप()' द्वारा फेंकने वाले अपवादों को पकड़ने के दक्षता पहलू के बारे में ज्यादा चिंता नहीं करता, लेकिन यदि आप चिंतित हैं स्टाइल तो आपका समाधान ठीक दिखता है। ध्यान दें कि आप शायद इसे एक सामान्य जेनेरिक विधि में उबलकर एपीआई कर सकते हैं, जहां टी को 'आउट' पैरामीटर द्वारा स्पष्ट रूप से निर्दिष्ट किया गया है। – Shog9

+0

मैं सब सादगी के लिए हूं, आपका मतलब क्या है "जहां टी को आउट पैरामीटर द्वारा स्पष्ट रूप से निर्दिष्ट किया गया है" ?? –

12

को देखते हुए यह: पूर्णांक, uint, लघु, ushort, लंबे, Ulong, बाइट, sbyte, दशमलव, नाव, डबल:

इसलिए टी निम्न में से कोई हो जाएगा।

मैं सिर्फ कनवर्ट का उपयोग करने की सिफारिश करता हूं। चेंज टाइप, और इसके बारे में चिंता न करें। एकमात्र समय आपको अपवाद मिलेगा जब आपकी स्ट्रिंग गलत रूप से स्वरूपित होती है, इस स्थिति में, आप डिफ़ॉल्ट (टी) वापस कर सकते हैं।

अर्थात्:

try 
{ 
    result = Convert.ChangeType(value, typeof(T)); 
} 
catch 
{ 
    result = default(T); 
} 
+0

टिप्पणी में उल्लिखित मैंने @ शोग 9 दिया, समस्या यह है क्योंकि मैं इसका उपयोग उपयोगकर्ता इनपुट को सत्यापित करने के लिए कर रहा हूं, मैं अपवाद उत्पन्न करने के ऊपरी हिस्से के बारे में चिंतित हूं। afaik एक अपवाद उत्पन्न करता है जिसे आप जानते हैं कि विधि चलाने के हर दूसरी बार एक महंगा ऑपरेशन हो सकता है, इसलिए मैं इसके बजाय प्रतिनिधियों का उपयोग करने की कोशिश क्यों कर रहा था। क्या आप यह कहेंगे कि प्रतिनिधि के दृष्टिकोण के बारे में सुझाए गए संस्करण के साथ अभी भी लायक है जिसका मैं उपयोग करने की कोशिश कर रहा हूं? –

+0

व्यक्तिगत रूप से, मैं अभी भी इसका उपयोग करता हूं। अपवादों का ऊपरी भाग ऐसा कुछ नहीं है जिसे मैं इस मामले में चिंता करता हूं, खासकर जब से, यदि यह उपयोगकर्ता इनपुट के लिए है, तो आपको इसे एक कसकर लूप में कॉल करने की आवश्यकता नहीं होगी (क्योंकि उपयोगकर्ता संभवत: तेज़ टाइप नहीं कर सकता आप अपवाद को संभाल सकते हैं)। आपके स्विच स्टेटमेंट, प्रतिनिधि कॉल इत्यादि में ओवरहेड होगा, यहां तक ​​कि अन्य दृष्टिकोण के साथ, और ऊपर की 6 लाइनों की तुलना में इसे बनाए रखने के लिए यह भयानक है। –

+0

मैं रीड से सहमत हूं। अपवाद सबसे खराब (ठंडा) पर मिलीसेकंड के दसियों के क्रम में कुछ ले सकता है; लेकिन अगर आप _one_ उपयोगकर्ता इनपुट स्ट्रिंग को मान्य कर रहे हैं, तो शायद ही यह ध्यान देने योग्य होगा। –

5

ToType सामान्य पैरामीटर यहाँ किया जा रहा है।यह शून्य प्रकार के लिए काम करता है, बस अगर आपको इसकी आवश्यकता होती है। आप एक सामान्य कनवर्टर होने के लिए अपनी मुख्य विधि निकाल सकते हैं, जो किसी भी प्रकार में परिवर्तित हो जाएगा, जिसमें नलिकाओं सहित।

ToType result = default(ToType);  

    result = ChangeType<ToType>(typedValue); 


    private T ChangeType<T>(object o) 
{ 
    Type conversionType = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T); 
    return (T)Convert.ChangeType(o, conversionType); 
} 
+0

यदि मैं इस दृष्टिकोण का उपयोग करता हूं तो यह कोशिश/पकड़ ब्लॉक की आवश्यकता के आसपास कैसे मिलता है ?? –

+0

अपवाद नहीं फेंक दिया जाएगा क्योंकि आप TryParse का उपयोग कर रहे हैं। यदि आपके TryParse का परिणाम सत्य है तो रूपांतरण तब तक काम करेगा जब तक कि आप पूरी तरह से अलग सामान्य पैरामीटर में पास नहीं हो जाते। क्या यह आपकी दुविधा है? –

+0

क्षमा करें आप एक अलग जेनेरिक पैरामीटर पास नहीं कर सकते हैं क्योंकि आपके पास टाइपफ़ोफ़ (टी) पर कोई कथन है .. तो आपका प्रश्न वास्तव में क्या है? –

1

क्यों न केवल प्रतिबिंब का उपयोग करें और TryParse विधियों में निर्मित का उपयोग क्यों करें? Guid के अपवाद के साथ हर देशी प्रकार के लिए बहुत ज्यादा एक।

public static Parser<T> GetParser<T>(T defaultResult) 
    where T : struct 
{ 
    // create parsing method 
    Parser<T> parser = (string value, out T result) => 
    { 
     // look for TryParse(string value,out T result) 
     var parseMethod = 
      typeof(T).GetMethods() 
        .Where(p => p.Name == "TryParse") 
        .Where(p => p.GetParameters().Length == 2) 
        .Single(); 

     // make parameters, leaving second element uninitialized means out/ref parameter 
     object[] parameters = new object[2]; 
     parameters[0] = value; 

     // run parse method 
     bool success = (bool)parseMethod.Invoke(null, parameters); 

     // if successful, set result to output 
     if (!success) 
     { 
      result = (T)parameters[1]; 
     } 
     else 
     { 
      result = defaultResult; 
     } 

     return success; 
    }; 

    return parser; 
} 
+0

यदि आप इसका परीक्षण करते हैं तो प्रदर्शन –

+0

प्रदर्शन के कारण प्रतिबिंब से बचने की कोशिश कर रहा हूं, आप 11 सेकंड में 100,000 से अधिक पार कर सकते हैं। मैंने मूल अभिव्यक्ति वृक्ष का उपयोग करके .NET 4 के विरुद्ध तुलना की, जिसमें 14 सेकंड लगे (हालांकि .net 4 जारी होने पर perf को प्रतिबिंबित नहीं किया जा सकता है) –

2

तुम कुछ सरल कोशिश कर सकते हैं

public static T ConvertValue<T,U>(U value) where U : IConvertible { 
     return (T)ConvertValue(value, typeof(T)); 
    } 

    public static object ConvertValue(IConvertible value, Type targetType) { 
     return Convert.ChangeType(value, targetType); 
    } 
संबंधित मुद्दे

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