जेनेरिक TryParse


196

मैं एक सामान्य एक्सटेंशन बनाने की कोशिश कर रहा हूँ जो 'स्ट्रिंग' दिए गए प्रकार की जाँच करने के लिए 'ट्रायपर्स' का उपयोग करता है:

public static bool Is<T>(this string input)
{
    T notUsed;
    return T.TryParse(input, out notUsed);
}

यह संकलन नहीं करेगा क्योंकि यह प्रतीक 'TryParse' को हल नहीं कर सकता है

जैसा कि मैं समझता हूं, 'ट्रायपर्स' किसी भी इंटरफेस का हिस्सा नहीं है।

क्या ऐसा करना संभव है?

अपडेट करें:

नीचे दिए गए उत्तरों का उपयोग करते हुए मैं आया हूँ:

public static bool Is<T>(this string input)
{
    try
    {
        TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(input);
    }
    catch
    {
        return false;
    }

    return true;
}

यह काफी अच्छी तरह से काम करता है, लेकिन मुझे लगता है कि इस तरह से अपवादों का उपयोग करना मुझे सही नहीं लगता।

Update2:

जेनरिक का उपयोग करने के बजाय टाइप पास करने के लिए संशोधित:

public static bool Is(this string input, Type targetType)
{
    try
    {
        TypeDescriptor.GetConverter(targetType).ConvertFromString(input);
        return true;
    }
    catch
    {
        return false;
    }
}

1
मुझे लगता है कि इस सामान्य मामले में आपको केवल अपवाद कीचड़ से निपटना होगा। आप चींटियों या युगल जैसी चीजों की जांच के लिए मामलों को जोड़ सकते हैं और फिर विशिष्ट TryParse विधियों का उपयोग कर सकते हैं, लेकिन अन्य प्रकारों को पकड़ने के लिए आपको अभी भी इस पर वापस आना होगा।
ल्यूक

1
जेनेरिक का उपयोग अनावश्यक है। बस टाइप करें एक पैरामीटर के रूप में। सार्वजनिक स्टेटिक बूल है (यह स्ट्रिंग इनपुट, टाइप टाइप टाइप)। इस तरह से कॉल करने पर यह थोड़ा प्रीतिकर लगता है: x.Is (टाइपोफ़ (int)) -VS- x.Is <int> ()
mikesigs

2
कन्वर्टर पर आपके पास यह जांचने के लिए कि क्या समस्याएँ हैं, के लिए एक अमान्य विधि है। मैंने नीचे दी गई विधि का उपयोग किया और ठीक काम करने लगता है। protected Boolean TryParse<T>(Object value, out T result) { result = default(T); var convertor = TypeDescriptor.GetConverter(typeof(T)); if (convertor == null || !convertor.IsValid(value)) { return false; } result = (T)convertor.ConvertFrom(value); return true; }
CastroXXL

@CastroXXL इस प्रश्न में रुचि दिखाने के लिए धन्यवाद, हालांकि आपका तरीका काफी काम नहीं करेगा क्योंकि मैं यह जांचना चाहता था कि क्या वस्तु के बजाय स्ट्रिंग मूल्य एक निश्चित प्रकार का था, हालांकि आपका तरीका ऑब्जेक्ट प्रकारों के लिए उपयोगी होगा (लेकिन अपवादों को पकड़ने के लिए ConvertFrom(value)एक try-catchब्लॉक में विधि को लपेटना होगा ।
पियर्स मायर्स

2
आपको यह देखना चाहिए कि क्या (targetType == null) क्योंकि आपके कोड में इसका पहला उपयोग फेंक सकता है, लेकिन यह अपवाद आपके कैच को निगल जाएगा।
निक स्ट्रूपट

जवाबों:


183

आपको TypeDescriptor वर्ग का उपयोग करना चाहिए :

public static T Convert<T>(this string input)
{
    try
    {
        var converter = TypeDescriptor.GetConverter(typeof(T));
        if(converter != null)
        {
            // Cast ConvertFromString(string text) : object to (T)
            return (T)converter.ConvertFromString(input);
        }
        return default(T);
    }
    catch (NotSupportedException)
    {
        return default(T);
    }
}

3
पुनर्जीवित करने के लिए क्षमा करें, लेकिन GetConverter वापस शून्य है? मुझे लगता है कि अगर ऐसा होता है तो संभवतः अनिवार्य रूप से चुपचाप विफल होने के बजाय एक अपवाद को फेंक दिया जाना चाहिए और कुछ और वापस करना चाहिए। जब मैंने इसे अपनी कक्षा में आज़माया (जिसमें मैंने टाइपकोनेक्सिफ़ायर को परिभाषित नहीं किया था), मुझे गेटकॉर्टर से एक कनवर्टर मिला, लेकिन फिर कन्वर्टफ्रॉमस्ट्रिंग ने एक NotSupportedException फेंक दिया।
user420667

3
@ user420667, मेरा मानना ​​है कि आपको स्ट्रिंग से कनवर्ट करने का प्रयास करने से पहले CanConvertFrom (टाइपोफ़ (स्ट्रिंग)) के परिणाम की जाँच करनी चाहिए। TypeConverter स्ट्रिंग से रूपांतरण का समर्थन नहीं कर सकता है।
रूबेन बॉन्ड

3
आप जोड़ सकते हैं यदि (टाइपोफ़ (टी)। आईसेनम) {रिटर्न (टी) एनम.पर्स (टाइपोफ़ (टी), इनपुट); } [कनवर्टर को प्राप्त करने से पहले सभी Enum प्रकारों के लिए एक काफी सामान्य शॉर्टकट के रूप में]। मुझे लगता है कि यह इस बात पर निर्भर करता है कि आप अधिक जटिल प्रकारों के विपरीत Enum प्रकार कितनी बार कर रहे होंगे।
जेसी चिशोल्म

10
मुझे समझ में नहीं आता है कि यह क्यों उत्तर के रूप में चिह्नित किया गया है और जब इसे लागू नहीं किया गया था तो बहुत कुछ उखाड़ दिया गया: एक सामान्य कोशिश पार्से। TryParse तरीकों का मुख्य उद्देश्य यह है कि वे अपवाद नहीं छोड़ते हैं जब पार्सिंग करने का प्रयास किया जाता है और प्रदर्शन पर बहुत कम प्रभाव पड़ता है जब पार्सिंग विफल हो जाती है और यह समाधान बस प्रदान करने में विफल रहता है।
फ्लोरिन डुमिट्रेस्कु

2
एक मुद्दा w / यह है कि यदि T एक int है और इनपुट int.MaxValue से बड़ा है, तो यह आंतरिक अपवाद के रूप में System.Exception w / System.OverFlowException को फेंक देगा। इसलिए यदि आप एक अतिप्रवाह अपवाद की उम्मीद कर रहे हैं, तो आप इसे तब तक नहीं प्राप्त करेंगे जब तक कि आप फेंकने वाले अपवाद से पूछताछ नहीं करते। कारण यह है कि ConvertFromString एक OverflowException को फेंकता है, और फिर T को कास्ट एक System.Exception को फेंकता है।
ट्रेवर

78

मुझे हाल ही में एक सामान्य TryParse की भी आवश्यकता थी। यहाँ मैं क्या लेकर आया हूँ;

public static T? TryParse<T>(string value, TryParseHandler<T> handler) where T : struct
{
    if (String.IsNullOrEmpty(value))
        return null;
    T result;
    if (handler(value, out result))
        return result;
    Trace.TraceWarning("Invalid value '{0}'", value);
    return null;
}

public delegate bool TryParseHandler<T>(string value, out T result);

तब यह केवल कॉल करने की बात है:

var value = TryParse<int>("123", int.TryParse);
var value2 = TryParse<decimal>("123.123", decimal.TryParse);

3
बस महीनों बाद फिर से इस पोस्ट पर आया और इसे फिर से उपयोग करते हुए देखा कि विधि Tहैंडलर से नहीं निकल सकती है , और Tजब हम इसे कहते हैं, तो हमें स्पष्ट रूप से निर्दिष्ट करना होगा। मैं उत्सुक हूँ, यह क्यों नहीं कर सकता T?
निक स्ट्रूपट

25
आप इस फ़ंक्शन का उपयोग क्यों करना चाहते हैं? यदि आप जानते हैं कि मूल्य को पार्स करने के लिए किस फ़ंक्शन को कॉल करना है, तो इसे सीधे कॉल क्यों न करें? यह पहले से ही सही इनपुट प्रकार जानता है और जेनरिक की कोई आवश्यकता नहीं है। यह समाधान TryParseHandler के बिना प्रकारों के लिए काम नहीं करेगा।
xxbbcc

2
@xxbbcc: मैं इस फ़ंक्शन का उपयोग करना चाहता हूं क्योंकि TryParse एक बूलियन देता है जो इंगित करता है कि क्या पार्स सफल था। यह आउटपुट पैरामीटर के माध्यम से आपके पार्स किए गए मान को लौटाता है। कभी-कभी मैं सिर्फ SomeMethod(TryParse<int>(DollarTextbox.Text, int.TryParse))परिणाम को पकड़ने के लिए आउटपुट चर बनाए बिना ऐसा कुछ करना चाहता हूं int.TryParse। हालाँकि, मैं फ़ंक्शन के प्रकार के बारे में निक की भावना से सहमत हूं।
वाल्टर स्टबोज़

1
बहुत कुशल विधि। अत्यधिक सिफारिशित।
व्लादिमीर कोकजेन्सिक

3
मैं तीसरे पैरा के रूप में एक डिफ़ॉल्ट मान की सिफारिश करूंगा। वह समस्या ठीक करता है जहाँ T का अनुमान नहीं लगाया जा सकता है। साथ ही, यह एक को यह तय करने की अनुमति देता है कि यदि स्ट्रिंग मान अमान्य है तो वे क्या मूल्य चाहते हैं। उदाहरण के लिए, -1 का मतलब अमान्य हो सकता है। सार्वजनिक स्थैतिक T TryParse <T> (स्ट्रिंग मान, TryParseHandler <T> हैंडलर, T
DefaultValue

33

प्रवाह नियंत्रण के लिए कोशिश / कैच का उपयोग करना एक भयानक नीति है। एक अपवाद को फेंकने के कारण प्रदर्शन लैग होता है जबकि अपवाद के आसपास रनटाइम काम करता है। इसके बजाय डेटा को कनवर्ट करने से पहले सत्यापित करें।

var attemptedValue = "asdfasdsd";
var type = typeof(int);
var converter = TypeDescriptor.GetConverter(type);
if (converter != null &&  converter.IsValid(attemptedValue))
    return converter.ConvertFromString(attemptedValue);
else
    return Activator.CreateInstance(type);

2
मुझे एक ऐसा रेस्परर नोटिस मिल रहा है जो converter != nullहमेशा सच होता है, इसलिए इसे कोड से हटाया जा सकता है।
एरिक

5
@ एरिक मैं हमेशा उन रेस्परर चेतावनियों पर भरोसा नहीं करता। अक्सर वे देख नहीं सकते कि रनटाइम पर क्या होता है।
ProfK

1
@ProfK MSDN यह नहीं कहता है कि यह null msdn.microsoft.com/en-us/library/ewtxwhzx.aspx
danio

@danio मैं सामान्य रूप से ऐसे R # चेतावनियों के साथ अपना अनुभव साझा कर रहा था। मैं निश्चित रूप से इसका मतलब यह नहीं था कि यह इस मामले में गलत था।
प्रोफ।

14

यदि आप TryParse का उपयोग कर रहे हैं, तो आप प्रतिबिंब का उपयोग कर सकते हैं और इसे इस तरह कर सकते हैं:

public static bool Is<T>(this string input)
{
    var type = typeof (T);
    var temp = default(T);
    var method = type.GetMethod(
        "TryParse",
        new[]
            {
                typeof (string),
                Type.GetType(string.Format("{0}&", type.FullName))
            });
    return (bool) method.Invoke(null, new object[] {input, temp});
}

यह बहुत अच्छा है, और यह उन अपवादों से छुटकारा दिलाता है जो मुझे वैसे भी पसंद नहीं थे। हालांकि अभी भी थोड़ा सा दोषी है।
पियर्स मायर्स

6
अच्छा समाधान है, लेकिन प्रतिबिंब से जुड़े किसी भी उत्तर (विशेष रूप से एक उपयोगिता पद्धति में जिसे आसानी से एक आंतरिक लूप से बुलाया जा सकता है) को प्रदर्शन के बारे में अस्वीकरण की आवश्यकता होती है। देखें: stackoverflow.com/questions/25458/how-costly-is-net-reflection
पैट्रिक एम।

आह। तो विकल्प हैं (1) कोड प्रवाह नियंत्रण के लिए अपवाद, (2) अपनी गति लागत के साथ प्रतिबिंब का उपयोग करें। मैं @PiersMyers से सहमत हूं - न तो विकल्प आदर्श है। अच्छी बात है कि वे दोनों काम करते हैं। :)
जेसी चिशोल्म

मुझे लगता है कि आप के Type.GetType(string.Format(...))साथ बदल सकते हैं type.MakeByRefType()
आकर्षित नोकें

3
विधि केवल प्रति बार एक बार परिलक्षित होनी चाहिए, एक बार प्रति कॉल नहीं। यदि आप इसे स्थिर सदस्य चर के साथ एक सामान्य वर्ग बनाते हैं, तो आप पहले प्रतिबिंब के आउटपुट का पुन: उपयोग कर सकते हैं।
एंड्रयू हिल

7

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

    public static bool TryParse<t>(this string Value, out t result)
    {
        return TryParser<t>.TryParse(Value.SafeTrim(), out result);
    }
    private delegate bool TryParseDelegate<t>(string value, out t result);
    private static class TryParser<T>
    {
        private static TryParseDelegate<T> parser;
        // Static constructor:
        static TryParser()
        {
            Type t = typeof(T);
            if (t.IsEnum)
                AssignClass<T>(GetEnumTryParse<T>());
            else if (t == typeof(bool) || t == typeof(bool?))
                AssignStruct<bool>(bool.TryParse);
            else if (t == typeof(byte) || t == typeof(byte?))
                AssignStruct<byte>(byte.TryParse);
            else if (t == typeof(short) || t == typeof(short?))
                AssignStruct<short>(short.TryParse);
            else if (t == typeof(char) || t == typeof(char?))
                AssignStruct<char>(char.TryParse);
            else if (t == typeof(int) || t == typeof(int?))
                AssignStruct<int>(int.TryParse);
            else if (t == typeof(long) || t == typeof(long?))
                AssignStruct<long>(long.TryParse);
            else if (t == typeof(sbyte) || t == typeof(sbyte?))
                AssignStruct<sbyte>(sbyte.TryParse);
            else if (t == typeof(ushort) || t == typeof(ushort?))
                AssignStruct<ushort>(ushort.TryParse);
            else if (t == typeof(uint) || t == typeof(uint?))
                AssignStruct<uint>(uint.TryParse);
            else if (t == typeof(ulong) || t == typeof(ulong?))
                AssignStruct<ulong>(ulong.TryParse);
            else if (t == typeof(decimal) || t == typeof(decimal?))
                AssignStruct<decimal>(decimal.TryParse);
            else if (t == typeof(float) || t == typeof(float?))
                AssignStruct<float>(float.TryParse);
            else if (t == typeof(double) || t == typeof(double?))
                AssignStruct<double>(double.TryParse);
            else if (t == typeof(DateTime) || t == typeof(DateTime?))
                AssignStruct<DateTime>(DateTime.TryParse);
            else if (t == typeof(TimeSpan) || t == typeof(TimeSpan?))
                AssignStruct<TimeSpan>(TimeSpan.TryParse);
            else if (t == typeof(Guid) || t == typeof(Guid?))
                AssignStruct<Guid>(Guid.TryParse);
            else if (t == typeof(Version))
                AssignClass<Version>(Version.TryParse);
        }
        private static void AssignStruct<t>(TryParseDelegate<t> del)
            where t: struct
        {
            TryParser<t>.parser = del;
            if (typeof(t).IsGenericType
                && typeof(t).GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                return;
            }
            AssignClass<t?>(TryParseNullable<t>);
        }
        private static void AssignClass<t>(TryParseDelegate<t> del)
        {
            TryParser<t>.parser = del;
        }
        public static bool TryParse(string Value, out T Result)
        {
            if (parser == null)
            {
                Result = default(T);
                return false;
            }
            return parser(Value, out Result);
        }
    }

    private static bool TryParseEnum<t>(this string Value, out t result)
    {
        try
        {
            object temp = Enum.Parse(typeof(t), Value, true);
            if (temp is t)
            {
                result = (t)temp;
                return true;
            }
        }
        catch
        {
        }
        result = default(t);
        return false;
    }
    private static MethodInfo EnumTryParseMethod;
    private static TryParseDelegate<t> GetEnumTryParse<t>()
    {
        Type type = typeof(t);

        if (EnumTryParseMethod == null)
        {
            var methods = typeof(Enum).GetMethods(
                BindingFlags.Public | BindingFlags.Static);
            foreach (var method in methods)
                if (method.Name == "TryParse"
                    && method.IsGenericMethodDefinition
                    && method.GetParameters().Length == 2
                    && method.GetParameters()[0].ParameterType == typeof(string))
                {
                    EnumTryParseMethod = method;
                    break;
                }
        }
        var result = Delegate.CreateDelegate(
            typeof(TryParseDelegate<t>),
            EnumTryParseMethod.MakeGenericMethod(type), false)
            as TryParseDelegate<t>;
        if (result == null)
            return TryParseEnum<t>;
        else
            return result;
    }

    private static bool TryParseNullable<t>(string Value, out t? Result)
        where t: struct
    {
        t temp;
        if (TryParser<t>.TryParse(Value, out temp))
        {
            Result = temp;
            return true;
        }
        else
        {
            Result = null;
            return false;
        }
    }

6

इस जैसे किसी और के बारे में क्या राय है?

http://madskristensen.net/post/Universal-data-type-checker.aspx ( पुरालेख )

/// <summary> 
/// Checks the specified value to see if it can be 
/// converted into the specified type. 
/// <remarks> 
/// The method supports all the primitive types of the CLR 
/// such as int, boolean, double, guid etc. as well as other 
/// simple types like Color and Unit and custom enum types. 
/// </remarks> 
/// </summary> 
/// <param name="value">The value to check.</param> 
/// <param name="type">The type that the value will be checked against.</param> 
/// <returns>True if the value can convert to the given type, otherwise false. </returns> 
public static bool CanConvert(string value, Type type) 
{ 
    if (string.IsNullOrEmpty(value) || type == null) return false;
    System.ComponentModel.TypeConverter conv = System.ComponentModel.TypeDescriptor.GetConverter(type);
    if (conv.CanConvertFrom(typeof(string)))
    { 
        try 
        {
            conv.ConvertFrom(value); 
            return true;
        } 
        catch 
        {
        } 
     } 
     return false;
  }

यह एक जेनेरिक विधि में आसानी से परिवर्तित किया जा सकता है।

 public static bool Is<T>(this string value)
 {
    if (string.IsNullOrEmpty(value)) return false;
    var conv = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));

    if (conv.CanConvertFrom(typeof(string)))
    { 
        try 
        {
            conv.ConvertFrom(value); 
            return true;
        } 
        catch 
        {
        } 
     } 
     return false;
}

इससे कोई फर्क नहीं पड़ता कि आप ट्रायल ब्लॉक से सही लौटें या कैच ब्लॉक से गलत लौटें? मुझे लगता है कि नहीं, लेकिन मुझे लगता है कि अभी भी इस तरह से अपवादों का उपयोग करना मेरे लिए गलत लगता है ...
पीयर्स मायर्स

3
इससे कोई फर्क नहीं पड़ता कि आप कैच ब्लॉक से लौटते हैं, यह वही है। btw। आमतौर पर सामान्य कैच क्लॉज होना बुरा है catch { }:। हालाँकि, इस मामले में कोई विकल्प नहीं है, क्योंकि .NET रूपांतरण त्रुटि के मामले में बेस क्लास को BaseNumberConverterफेंकता है Exception। यह बहुत दुर्भाग्यपूर्ण है। वास्तव में वहाँ अभी भी काफी कुछ स्थानों पर इस आधार प्रकार फेंक दिया गया है। उम्मीद है कि Microsoft फ्रेमवर्क के भविष्य के संस्करण में इन्हें ठीक कर देगा।
स्टीवन

धन्यवाद स्टीवन, इसे बेहतर नहीं कह सकते थे।
बॉब

रूपांतरण के परिणाम से बना कोई उपयोग नहीं: कोड निरर्थक है।
बिल्व्ड

4

आप इसे सामान्य प्रकारों पर नहीं कर सकते।

आप क्या कर सकते हैं एक इंटरफ़ेस ITryParsable बनाने के लिए और इसे कस्टम प्रकारों के लिए उपयोग करें जो इस इंटरफ़ेस को लागू करते हैं।

हालांकि मुझे लगता है कि आप इसे मूल प्रकारों के साथ उपयोग करने का इरादा रखते हैं intऔर DateTime। आप नए इंटरफेस को लागू करने के लिए इन प्रकारों को बदल नहीं सकते हैं।


1
मुझे आश्चर्य है कि अगर यह .net 4 में डायनामिक कीवर्ड का उपयोग करके काम करेगा?
पियरे-एलेन विगेंट

@ पिएरे: यह dynamicकीवर्ड के साथ C # में डिफ़ॉल्ट रूप से काम नहीं करेगा , क्योंकि यह स्थैतिक टाइपिंग पर काम नहीं करेगा। आप अपनी खुद की गतिशील वस्तु बना सकते हैं जो इसे संभाल सकती है, लेकिन यह डिफ़ॉल्ट नहीं है।
स्टीवन

4

चार्ली ब्राउन द्वारा यहां पोस्ट किए गए समाधान से प्रेरित होकर, मैंने प्रतिबिंब का उपयोग करते हुए एक जेनेरिक TryParse बनाया जो वैकल्पिक रूप से pededed आउटपुट देता है:

/// <summary>
/// Tries to convert the specified string representation of a logical value to
/// its type T equivalent. A return value indicates whether the conversion
/// succeeded or failed.
/// </summary>
/// <typeparam name="T">The type to try and convert to.</typeparam>
/// <param name="value">A string containing the value to try and convert.</param>
/// <param name="result">If the conversion was successful, the converted value of type T.</param>
/// <returns>If value was converted successfully, true; otherwise false.</returns>
public static bool TryParse<T>(string value, out T result) where T : struct {
    var tryParseMethod = typeof(T).GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, null, new [] { typeof(string), typeof(T).MakeByRefType() }, null);
    var parameters = new object[] { value, null };

    var retVal = (bool)tryParseMethod.Invoke(null, parameters);

    result = (T)parameters[1];
    return retVal;
}

/// <summary>
/// Tries to convert the specified string representation of a logical value to
/// its type T equivalent. A return value indicates whether the conversion
/// succeeded or failed.
/// </summary>
/// <typeparam name="T">The type to try and convert to.</typeparam>
/// <param name="value">A string containing the value to try and convert.</param>
/// <returns>If value was converted successfully, true; otherwise false.</returns>
public static bool TryParse<T>(string value) where T : struct {
    T throwaway;
    var retVal = TryParse(value, out throwaway);
    return retVal;
}

इसे इस प्रकार कहा जा सकता है:

string input = "123";
decimal myDecimal;

bool myIntSuccess = TryParse<int>(input);
bool myDecimalSuccess = TryParse<decimal>(input, out myDecimal);

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

/// <summary>
/// Provides some extra parsing functionality for value types.
/// </summary>
/// <typeparam name="T">The value type T to operate on.</typeparam>
public static class TryParseHelper<T> where T : struct {
    private delegate bool TryParseFunc(string str, out T result);

    private static TryParseFunc tryParseFuncCached;

    private static TryParseFunc tryParseCached {
        get {
            return tryParseFuncCached ?? (tryParseFuncCached = Delegate.CreateDelegate(typeof(TryParseFunc), typeof(T), "TryParse") as TryParseFunc);
        }
    }

    /// <summary>
    /// Tries to convert the specified string representation of a logical value to
    /// its type T equivalent. A return value indicates whether the conversion
    /// succeeded or failed.
    /// </summary>
    /// <param name="value">A string containing the value to try and convert.</param>
    /// <param name="result">If the conversion was successful, the converted value of type T.</param>
    /// <returns>If value was converted successfully, true; otherwise false.</returns>
    public static bool TryParse(string value, out T result) {
        return tryParseCached(value, out result);
    }

    /// <summary>
    /// Tries to convert the specified string representation of a logical value to
    /// its type T equivalent. A return value indicates whether the conversion
    /// succeeded or failed.
    /// </summary>
    /// <param name="value">A string containing the value to try and convert.</param>
    /// <returns>If value was converted successfully, true; otherwise false.</returns>
    public static bool TryParse(string value) {
        T throwaway;
        return TryParse(value, out throwaway);
    }
}

इसे इस तरह से कॉल करें:

string input = "987";
decimal myDecimal;

bool myIntSuccess = TryParseHelper<int>.TryParse(input);
bool myDecimalSuccess = TryParseHelper<decimal>.TryParse(input, out myDecimal);

3

पार्टी के लिए थोड़ी देर हो गई, लेकिन यहाँ मैं क्या लेकर आया हूँ। कोई अपवाद नहीं, एक बार (प्रति प्रकार) प्रतिबिंब।

public static class Extensions {
    public static T? ParseAs<T>(this string str) where T : struct {
        T val;
        return GenericHelper<T>.TryParse(str, out val) ? val : default(T?);
    }
    public static T ParseAs<T>(this string str, T defaultVal) {
        T val;
        return GenericHelper<T>.TryParse(str, out val) ? val : defaultVal;
    }

    private static class GenericHelper<T> {
        public delegate bool TryParseFunc(string str, out T result);

        private static TryParseFunc tryParse;
        public static TryParseFunc TryParse {
            get {
                if (tryParse == null)
                    tryParse = Delegate.CreateDelegate(
                        typeof(TryParseFunc), typeof(T), "TryParse") as TryParseFunc;
                return tryParse;
            }
        }
    }
}

अतिरिक्त वर्ग की आवश्यकता है क्योंकि जेनेरिक कक्षाओं के अंदर बाहर निकालने के तरीकों की अनुमति नहीं है। यह सरल उपयोग की अनुमति देता है, जैसा कि नीचे दिखाया गया है, और केवल हिट का प्रतिबिंब पहली बार एक प्रकार का उपयोग किया जाता है।

"5643".ParseAs<int>()

3

यहाँ एक और विकल्प है।

मैंने एक वर्ग लिखा है जो किसी भी संख्या में TryParseसंचालकों को पंजीकृत करना आसान बनाता है । यह मुझे ऐसा करने देता है:

var tp = new TryParser();

tp.Register<int>(int.TryParse);
tp.Register<decimal>(decimal.TryParse);
tp.Register<double>(double.TryParse);

int x;
if (tp.TryParse("42", out x))
{
    Console.WriteLine(x);
};

मैं 42सांत्वना के लिए मुद्रित हो।

वर्ग है:

public class TryParser
{
    public delegate bool TryParseDelegate<T>(string s, out T result);

    private Dictionary<Type, Delegate> _tryParsers = new Dictionary<Type, Delegate>();

    public void Register<T>(TryParseDelegate<T> d)
    {
        _tryParsers[typeof(T)] = d;
    }

    public bool Deregister<T>()
    {
        return _tryParsers.Remove(typeof(T));
    }

    public bool TryParse<T>(string s, out T result)
    {
        if (!_tryParsers.ContainsKey(typeof(T)))
        {
            throw new ArgumentException("Does not contain parser for " + typeof(T).FullName + ".");
        }
        var d = (TryParseDelegate<T>)_tryParsers[typeof(T)];
        return d(s, out result);
    }
}

मुझे यह पसंद है, लेकिन आप इसे बिना जेनरिक के कैसे करेंगे। केस रिफ्लेक्शन का इस्तेमाल करें।
सिनास्टैटिक

मैंने एक अतिभारित तरीका जोड़ा जो कुछ प्रतिबिंब हैकरी करता है। यदि इसे संबोधित करने का एक और अधिक सुंदर तरीका है, तो मैं सभी आंखें lol gist.github.com/dasjestyr/90d8ef4dea179a6e08ddd85e0dacbc94
Sinaestr

2

जब मैं लगभग इस सटीक कार्य को करना चाहता था, तो मुझे प्रतिबिंब को देखते हुए इसे कठिन तरीके से लागू करना था। यह देखते हुए T, पर प्रतिबिंबित typeof(T)और एक के लिए रंग-रूप TryParseया Parseविधि है, यह लागू करता है, तो आपको यह मिल गया।


यह मैं सुझाव देने वाला था।
स्टीवन एवर्स

2

यह मेरी कोशिश है। मैंने इसे "व्यायाम" के रूप में किया। मैंने इसे मौजूदा " Convert.ToX () " -ones आदि के रूप में उपयोग करने के समान बनाने की कोशिश की, लेकिन यह एक विस्तार विधि है:

    public static bool TryParse<T>(this String str, out T parsedValue)
    {
        try
        {
            parsedValue = (T)Convert.ChangeType(str, typeof(T));
            return true;
        }

        catch { parsedValue = default(T); return false; }
    }

इसके साथ तुलना में मुख्य नुकसान यह TypeConverter.ConvertFrom()है कि स्रोत वर्ग को टाइप रूपांतरण प्रदान करना है, जिसका आम तौर पर मतलब है कि आप कस्टम प्रकारों में रूपांतरण का समर्थन नहीं कर सकते।
इयान गोल्डबी

1

जैसा कि आपने कहा, TryParseएक इंटरफ़ेस का हिस्सा नहीं है। यह किसी भी दिए गए आधार वर्ग का सदस्य नहीं है क्योंकि यह वास्तव में है staticऔर staticकार्य नहीं किया जा सकता है virtual। इसलिए, संकलक के पास यह आश्वासन देने का कोई तरीका नहीं है कि Tवास्तव में एक सदस्य को बुलाया गया है TryParse, इसलिए यह काम नहीं करता है।

जैसा कि @ मर्क ने कहा, आप अपना स्वयं का इंटरफ़ेस बना सकते हैं और कस्टम प्रकारों का उपयोग कर सकते हैं, लेकिन आप अंतर्निहित प्रकारों के लिए भाग्य से बाहर हैं।


1
public static class Primitive
{
    public static DateTime? TryParseExact(string text, string format, IFormatProvider formatProvider = null, DateTimeStyles? style = null)
    {
        DateTime result;
        if (DateTime.TryParseExact(text, format, formatProvider, style ?? DateTimeStyles.None, out result))
            return result;
        return null;
    }

    public static TResult? TryParse<TResult>(string text) where TResult : struct
    {
        TResult result;
        if (Delegates<TResult>.TryParse(text, out result))
            return result;
        return null;
    }

    public static bool TryParse<TResult>(string text, out TResult result) => Delegates<TResult>.TryParse(text, out result);

    public static class Delegates<TResult>
    {
        private delegate bool TryParseDelegate(string text, out TResult result);

        private static readonly TryParseDelegate _parser = (TryParseDelegate)Delegate.CreateDelegate(typeof(TryParseDelegate), typeof(TResult), "TryParse");

        public static bool TryParse(string text, out TResult result) => _parser(text, out result);
    }
}

0

यह 'सामान्य बाधाओं' का सवाल है। क्योंकि आपके पास कोई विशिष्ट इंटरफ़ेस नहीं है तो आप तब तक अटके रहते हैं जब तक कि आप पिछले उत्तर के सुझावों का पालन नहीं करते हैं।

इस पर प्रलेखन के लिए, निम्न लिंक की जाँच करें:

http://msdn.microsoft.com/en-us/library/ms379564(VS.80).aspx

यह आपको दिखाता है कि इन बाधाओं का उपयोग कैसे करें और आपको कुछ और सुराग देने चाहिए।


0

Http://blogs.msdn.com/b/davidebb/archive/2009/10/23/use-c-dynamic-to-call-static-members.aspx से उधार लिया गया

इस संदर्भ का अनुसरण करते समय: गतिशील प्रकार के साथ C # 4.0 में स्थिर विधि कैसे लागू करें?

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Reflection;

namespace Utils
{
   public class StaticMembersDynamicWrapper : DynamicObject
   {
      private Type _type;

      public StaticMembersDynamicWrapper(Type type) { _type = type; }

      // Handle static methods
      public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
      {
         var methods = _type
            .GetMethods(BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public)
            .Where(methodInfo => methodInfo.Name == binder.Name);

         var method = methods.FirstOrDefault();
         if (method != null)
         {
            result = method.Invoke(null, args);
            return true;
         }

         result = null;
         return false;
      }
   }

   public static class StaticMembersDynamicWrapperExtensions
   {
      static Dictionary<Type, DynamicObject> cache =
         new Dictionary<Type, DynamicObject>
         {
            {typeof(double), new StaticMembersDynamicWrapper(typeof(double))},
            {typeof(float), new StaticMembersDynamicWrapper(typeof(float))},
            {typeof(uint), new StaticMembersDynamicWrapper(typeof(uint))},
            {typeof(int), new StaticMembersDynamicWrapper(typeof(int))},
            {typeof(sbyte), new StaticMembersDynamicWrapper(typeof(sbyte))}
         };

      /// <summary>
      /// Allows access to static fields, properties, and methods, resolved at run-time.
      /// </summary>
      public static dynamic StaticMembers(this Type type)
      {
         DynamicObject retVal;
         if (!cache.TryGetValue(type, out retVal))
            return new StaticMembersDynamicWrapper(type);

         return retVal;
      }
   }
}

और इसे निम्नानुसार उपयोग करें:

  public static T? ParseNumeric<T>(this string str, bool throws = true)
     where T : struct
  {
     var statics = typeof(T).StaticMembers();

     if (throws) return statics.Parse(str);

     T retval;
     if (!statics.TryParse(str, out retval)) return null;

     return retval;
  }

0

मैं कुछ ऐसा पाने में कामयाब रहा जो इस तरह से काम करता है

    var result = "44".TryParse<int>();

    Console.WriteLine( "type={0}, value={1}, valid={2}",        
    result.Value.GetType(), result.Value, result.IsValid );

यहाँ मेरा कोड है

 public static class TryParseGeneric
    {
        //extend int
        public static dynamic TryParse<T>( this string input )
        {    
            dynamic runner = new StaticMembersDynamicWrapper( typeof( T ) );

            T value;
            bool isValid = runner.TryParse( input, out value );
            return new { IsValid = isValid, Value = value };
        }
    }


    public class StaticMembersDynamicWrapper : DynamicObject
    {
        private readonly Type _type;
        public StaticMembersDynamicWrapper( Type type ) { _type = type; }

        // Handle static properties
        public override bool TryGetMember( GetMemberBinder binder, out object result )
        {
            PropertyInfo prop = _type.GetProperty( binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public );
            if ( prop == null )
            {
                result = null;
                return false;
            }

            result = prop.GetValue( null, null );
            return true;
        }

        // Handle static methods
        public override bool TryInvokeMember( InvokeMemberBinder binder, object [] args, out object result )
        {
            var methods = _type
            .GetMethods( BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public ).Where( methodInfo => methodInfo.Name == binder.Name );

            var method = methods.FirstOrDefault();

            if ( method == null )
            {
                result = null;

                return false;
            }

            result = method.Invoke( null, args );

            return true;
        }
    }

StaticMembersDynamicWrapper डेविड Ebbo के लेख से अनुकूलित है (यह एक AmbiguousMatchException फेंक रहा था)


0
public static T Get<T>(string val)
{ 
    return (T) TypeDescriptor.GetConverter(typeof (T)).ConvertFromInvariantString(val);
}

0

संबंधित तरीके से TypeDescriptorवर्ग उपयोग के साथ TryParse:

public static bool TryParse<T>(this string input, out T parsedValue)
{
    parsedValue = default(T);
    try
    {
        var converter = TypeDescriptor.GetConverter(typeof(T));
        parsedValue = (T)converter.ConvertFromString(input);
        return true;
    }
    catch (NotSupportedException)
    {
        return false;
    }
}

हालांकि यह कोड प्रश्न को हल कर सकता है, जिसमें यह भी बताया गया है कि यह समस्या कैसे और क्यों हल करती है, इससे वास्तव में आपके पोस्ट की गुणवत्ता को बेहतर बनाने में मदद मिलेगी, और संभवत: अधिक वोट मिले। याद रखें कि आप भविष्य में पाठकों के लिए सवाल का जवाब दे रहे हैं, न कि केवल उस व्यक्ति से जो अब पूछ रहा है। कृपया स्पष्टीकरण जोड़ने के लिए अपने उत्तर को संपादित करें और संकेत दें कि क्या सीमाएँ और मान्यताएँ लागू होती हैं।
डबल-बीप

0

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

मैं एक शब्दकोश में विधियों को कैश करता हूं क्योंकि प्रत्येक विधि को लोड करने की विधि को कम करने के लिए सामना किया गया है।

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

    /// <summary>
    /// Used to store TryParse converter methods
    /// </summary>
    private static readonly Dictionary<Type, MethodInfo> TypeConverters = new Dictionary<Type, MethodInfo>();

    /// <summary>
    /// Attempt to parse the input object to the output type
    /// </summary>
    /// <typeparam name="T">output type</typeparam>
    /// <param name="obj">input object</param>
    /// <param name="result">output result on success, default(T) on failure</param>
    /// <returns>Success</returns>
    public static bool TryParse<T>([CanBeNull] object obj, out T result)
    {
        result = default(T);

        try
        {
            switch (obj)
            {
                // don't waste time on null objects
                case null: return false;

                // if the object is already of type T, just return the value
                case T val:
                    result = val;
                    return true;
            }

            // convert the object into type T via string conversion
            var input = ((obj as string) ?? obj.ToString()).Trim();
            if (string.IsNullOrEmpty(input)) return false;

            var type = typeof (T);
            Debug.WriteLine($"Info: {nameof(TryParse)}<{type.Name}>({obj.GetType().Name}=\"{input}\")");

            if (! TypeConverters.TryGetValue(type, out var method))
            {
                // get the TryParse method for this type
                method = type.GetMethod("TryParse",
                    new[]
                    {
                        typeof (string),
                        Type.GetType($"{type.FullName}&")
                    });

                if (method is null)
                    Debug.WriteLine($"FAILED: Cannot get method for {type.Name}.TryParse()");

                // store it so we don't have to do this again
                TypeConverters.Add(type, method);
            }

            // have to keep a reference to parameters if you want to get the returned ref value
            var parameters = new object[] {input, null};
            if ((bool?) method?.Invoke(null, parameters) == true)
            {
                result = (T) parameters[1];
                return true;
            }                
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }

        return false;
    }

मुझे एनुमरेशन्स को सपोर्ट करने के लिए एक और फंक्शन जोड़ना पड़ा। लगता है Enum पार्सिंग के लिए "जहां T: संरचना" विशेषता की आवश्यकता होती है, और मैं चाहता हूं कि यह किसी भी परिवर्तनीय पर काम करे। (शायद प्रकार में एक परिवर्तनीय विशेषता जोड़ना चाहिए)। हालांकि, निम्नलिखित सुझावों में से कुछ सरल (इस प्रकार बेहतर) दिखते हैं।
बी डफी

0

मैंने यहां विचारों का एक समूह रखा और एक बहुत ही छोटे समाधान के साथ समाप्त हुआ।

यह एक स्ट्रिंग पर एक विस्तार विधि है

enter code here

मैंने इसे संख्यात्मक प्रकारों पर TryParse विधियों के समान फ़ुट प्रिंट के साथ बनाया

    /// <summary>
    /// string.TryParse()
    /// 
    /// This generic extension method will take a string
    ///     make sure it is not null or empty
    ///     make sure it represents some type of number e.g. "123" not "abc"
    ///     It then calls the appropriate converter for the type of T
    /// </summary>
    /// <typeparam name="T">The type of the desired retrunValue e.g. int, float, byte, decimal...</typeparam>
    /// <param name="targetText">The text to be converted</param>
    /// <param name="returnValue">a populated value of the type T or the default(T) value which is likely to be 0</param>
    /// <returns>true if the string was successfully parsed and converted otherwise false</returns>
    /// <example>
    /// float testValue = 0;
    ///  if ( "1234".TryParse<float>( out testValue ) )
    ///  {
    ///      doSomethingGood();
    ///  }
    ///  else
    ///  {
    ///      handleTheBadness();
    ///  }
    /// </example>
    public static bool TryParse<T>(this string targetText, out T returnValue )
    {
        bool returnStatus = false;

        returnValue = default(T);

        //
        // make sure the string is not null or empty and likely a number...
        // call whatever you like here or just leave it out - I would
        // at least make sure the string was not null or empty  
        //
        if ( ValidatedInputAnyWayYouLike(targetText) )
        {

            //
            // try to catch anything that blows up in the conversion process...
            //
            try
            {
                var type = typeof(T);
                var converter = TypeDescriptor.GetConverter(type);

                if (converter != null && converter.IsValid(targetText))
                {
                    returnValue = (T)converter.ConvertFromString(targetText);
                    returnStatus = true;
                }

            }
            catch
            {
                // just swallow the exception and return the default values for failure
            }

        }

        return (returnStatus);

    }

'' '


फ्लोट टेस्टवैल्यू = 0; अगर ("1234" } और {हैंडलTheBadness (); }
जेडी हिक्स

0

T.TryParse ... क्यों?

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

  • समर्पित TryParse फ़ंक्शन के साथ कक्षाएं बुलाई जा सकती हैं
  • समर्पित कार्यों के साथ कक्षाएं ट्राइ-कैच और बूल परिणाम के साथ लपेटी जा सकती हैं
  • ऑपरेटर अधिभार के साथ कक्षाएं, आप उन्हें पार्सिंग को कैसे संभालने देंगे?
  • प्रकार वर्णनकर्ता अंतर्निहित उपयोग में हैं Convert.ChangeType। यह एपीआई रनटाइम पर अनुकूलन योग्य है। क्या आपके फ़ंक्शन को डिफ़ॉल्ट व्यवहार की आवश्यकता है या अनुकूलन की अनुमति है?
  • क्या आपको किसी भी मानचित्रण ढांचे को आपके लिए पार्स करने की कोशिश करने की अनुमति देनी चाहिए?
  • आप उपरोक्त में संघर्षों को कैसे संभालेंगे?

-2

XDocument से वंश प्राप्त करने के लिए एक संस्करण।

public static T Get<T>(XDocument xml, string descendant, T @default)
{
    try
    {
        var converter = TypeDescriptor.GetConverter(typeof (T));
        if (converter != null)
        {
            return (T) converter.ConvertFromString(xml.Descendants(descendant).Single().Value);
        }
        return @default;
    }
    catch
    {
        return @default;
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.