c# - जेनेरिक TryParse




generics (16)

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

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

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

जैसा कि मैं समझता हूं, '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;
    }
}

Answers

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

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>()

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

इस पर दस्तावेज़ के लिए, निम्न लिंक देखें:

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

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


आपको 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);
    }
}

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

यह मेरी कोशिश है। मैंने इसे "अभ्यास" के रूप में किया। मैंने इसे मौजूदा "कन्वर्ट.ओएक्स () " -ऑन इत्यादि के रूप में उपयोग करने के समान बनाने की कोशिश की लेकिन यह एक विस्तार विधि है:

    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; }
    }

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

/// <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);

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

/// <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);

मुझे हाल ही में एक सामान्य 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);

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

http://madskristensen.net/post/Universal-data-type-checker.aspx ( Archive )

/// <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 T Is<T>(this string input)
 {
    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;
}

यदि आप 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});
}

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

    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;
        }
    }

स्टेटिक मेम्बरर्स डायनामिकवापर को डेविड एबो के http://blogs.msdn.com/b/davidebb/archive/2009/10/23/using-c-dynamic-to-call-static-members.aspx से अनुकूलित किया गया है (यह एक अस्पष्ट मैच अपवाद फेंक रहा था)


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;
    }
}

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

    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;
        }
    }

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

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


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


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

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);

 int n = new Random().Next();

आप Next() फ़ंक्शन को न्यूनतम और अधिकतम मान भी दे सकते हैं। पसंद

 int n = new Random().Next(5,10);






c# generics tryparse