c# एक एनम के लिए टी बाध्यकारी जेनेरिक विधि बनाएँ




generics enums (15)

मैंने थोड़ा सा कोड सुधारने की कोशिश की:

public T LoadEnum<T>(string value, T defaultValue = default(T)) where T : struct, IComparable, IFormattable, IConvertible
{
    if (Enum.IsDefined(typeof(T), value))
    {
        return (T)Enum.Parse(typeof(T), value, true);
    }
    return defaultValue;
}

मैं Enum.Parse अवधारणा को बढ़ाने के लिए एक समारोह का निर्माण कर रहा हूँ

  • यदि कोई एनम मान नहीं मिलता है तो डिफ़ॉल्ट मान को पार्स किया जा सकता है
  • मामला असंवेदनशील है

तो मैंने निम्नलिखित लिखा:

public static T GetEnumFromString<T>(string value, T defaultValue) where T : Enum
{
    if (string.IsNullOrEmpty(value)) return defaultValue;
    foreach (T item in Enum.GetValues(typeof(T)))
    {
        if (item.ToString().ToLower().Equals(value.Trim().ToLower())) return item;
    }
    return defaultValue;
}

मुझे एक त्रुटि प्रतिबंध मिल रहा है विशेष वर्ग 'System.Enum' नहीं हो सकता है।

काफी उचित है, लेकिन क्या जेनेरिक एनम की अनुमति देने के लिए कोई कामकाज है, या मुझे पर्स फ़ंक्शन की नकल करने और एक प्रकार के रूप में एक प्रकार के रूप में पास करने की आवश्यकता है, जो आपके कोड पर बदसूरत मुक्केबाजी आवश्यकता को मजबूर करता है।

संपादित करें नीचे दिए गए सभी सुझावों की बहुत सराहना की गई है, धन्यवाद।

इस पर बस गए हैं (मैंने केस असंवेदनशीलता को बनाए रखने के लिए लूप छोड़ा है - एक्सएमएल पार्स करते समय मैं इसका उपयोग कर रहा हूं)

public static class EnumUtils
{
    public static T ParseEnum<T>(string value, T defaultValue) where T : struct, IConvertible
    {
        if (!typeof(T).IsEnum) throw new ArgumentException("T must be an enumerated type");
        if (string.IsNullOrEmpty(value)) return defaultValue;

        foreach (T item in Enum.GetValues(typeof(T)))
        {
            if (item.ToString().ToLower().Equals(value.Trim().ToLower())) return item;
        }
        return defaultValue;
    }
}

संपादित करें: (16 फरवरी 2015) जूलियन लेबोस्क्वेन ने हाल ही में एमएसआईएल या एफ # में एक कंपाइलर लागू प्रकार-सुरक्षित जेनेरिक समाधान पोस्ट किया है , जो एक लुक के लायक है, और एक अपवर्तनीय है। यदि समाधान बुलबुले पृष्ठ को आगे बढ़ाता है तो मैं इस संपादन को हटा दूंगा।


यह मेरा लेना है। उत्तर और एमएसडीएन से संयुक्त

public static TEnum ParseToEnum<TEnum>(this string text) where TEnum : struct, IConvertible, IComparable, IFormattable
{
    if (string.IsNullOrEmpty(text) || !typeof(TEnum).IsEnum)
        throw new ArgumentException("TEnum must be an Enum type");

    try
    {
        var enumValue = (TEnum)Enum.Parse(typeof(TEnum), text.Trim(), true);
        return enumValue;
    }
    catch (Exception)
    {
        throw new ArgumentException(string.Format("{0} is not a member of the {1} enumeration.", text, typeof(TEnum).Name));
    }
}

एमएसडीएन स्रोत


आप बाधा विरासत का दुरुपयोग करके एक असली संकलक लागू enum बाधा हो सकती है। निम्न कोड एक ही समय में एक class और struct बाधाओं को निर्दिष्ट करता है:

public abstract class EnumClassUtils<TClass>
where TClass : class
{

    public static TEnum Parse<TEnum>(string value)
    where TEnum : struct, TClass
    {
        return (TEnum) Enum.Parse(typeof(TEnum), value);
    }

}

public class EnumUtils : EnumClassUtils<Enum>
{
}

उपयोग:

EnumUtils.Parse<SomeEnum>("value");

नोट: यह विशेष रूप से सी # 5.0 भाषा विनिर्देश में कहा गया है:

यदि टाइप पैरामीटर एस टाइप पैरामीटर टी पर निर्भर करता है तो: [...] यह मान प्रकार की बाधा और टी को संदर्भ प्रकार बाधा रखने के लिए मान्य है। प्रभावी रूप से यह सिस्टम को सिस्टम को सीमित करता है। ऑब्जेक्ट, सिस्टम। वैल्यू टाइप, सिस्टम.इनम, और कोई इंटरफ़ेस प्रकार।


मुझे आईएल का उपयोग करके क्रिस्टोफर कर्रेन के समाधान से प्यार था, लेकिन उन लोगों के लिए जो एमएसआईएल को अपनी निर्माण प्रक्रिया में शामिल करने के मुश्किल व्यवसाय से निपटना नहीं चाहते हैं, मैंने सी # में इसी तरह के कार्य को लिखा था।

कृपया ध्यान दें कि आप जेनेरिक प्रतिबंध का उपयोग नहीं कर सकते हैं जैसे where T : Enum क्योंकि एनम विशेष प्रकार है। इसलिए मुझे यह जांचना है कि दिया गया सामान्य प्रकार वास्तव में enum है या नहीं।

मेरा कार्य है:

public static T GetEnumFromString<T>(string strValue, T defaultValue)
{
    // Check if it realy enum at runtime 
    if (!typeof(T).IsEnum)
        throw new ArgumentException("Method GetEnumFromString can be used with enums only");

    if (!string.IsNullOrEmpty(strValue))
    {
        IEnumerator enumerator = Enum.GetValues(typeof(T)).GetEnumerator();
        while (enumerator.MoveNext())
        {
            T temp = (T)enumerator.Current;
            if (temp.ToString().ToLower().Equals(strValue.Trim().ToLower()))
                return temp;
        }
    }

    return defaultValue;
}

उम्मीद है कि यह सहायक है:

public static TValue ParseEnum<TValue>(string value, TValue defaultValue)
                  where TValue : struct // enum 
{
      try
      {
            if (String.IsNullOrEmpty(value))
                  return defaultValue;
            return (TValue)Enum.Parse(typeof (TValue), value);
      }
      catch(Exception ex)
      {
            return defaultValue;
      }
}

मैंने विधि कार्यान्वयन को देखने के लिए to get integer value from enum एक विस्तार विधि बनाई है

public static int ToInt<T>(this T soure) where T : IConvertible//enum
{
    if (typeof(T).IsEnum)
    {
        return (int) (IConvertible)soure;// the tricky part
    }
    //else
    //    throw new ArgumentException("T must be an enumerated type");
    return soure.ToInt32(CultureInfo.CurrentCulture);
}

यह उपयोग है

MemberStatusEnum.Activated.ToInt()// using extension Method
(int) MemberStatusEnum.Activated //the ordinary way

मौजूदा उत्तर C # <= 7.2 के रूप में सत्य हैं। हालांकि, निम्नलिखित की अनुमति देने के लिए एक सी # भाषा सुविधा अनुरोध ( corefx सुविधा अनुरोध से जुड़ा हुआ है);

public class MyGeneric<TEnum> where TEnum : System.Enum
{ }

लेखन के समय, भाषा विकास बैठक में यह सुविधा "चर्चा में" है।

संपादित करें

की जानकारी के अनुसार, यह सी # 7.3 में पेश किया जा रहा है।


संपादित करें

जूलियन लेबोस्क्वेन ने अब सवाल का जवाब दिया है। TryParse और ParseOrDefault जोड़ने के दौरान, मैं ignoreCase , ignoreCase और वैकल्पिक तर्कों के साथ अपना उत्तर भी विस्तारित करना चाहता हूं।

public abstract class ConstrainedEnumParser<TClass> where TClass : class
// value type constraint S ("TEnum") depends on reference type T ("TClass") [and on struct]
{
    // internal constructor, to prevent this class from being inherited outside this code
    internal ConstrainedEnumParser() {}
    // Parse using pragmatic/adhoc hard cast:
    //  - struct + class = enum
    //  - 'guaranteed' call from derived <System.Enum>-constrained type EnumUtils
    public static TEnum Parse<TEnum>(string value, bool ignoreCase = false) where TEnum : struct, TClass
    {
        return (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase);
    }
    public static bool TryParse<TEnum>(string value, out TEnum result, bool ignoreCase = false, TEnum defaultValue = default(TEnum)) where TEnum : struct, TClass // value type constraint S depending on T
    {
        var didParse = Enum.TryParse(value, ignoreCase, out result);
        if (didParse == false)
        {
            result = defaultValue;
        }
        return didParse;
    }
    public static TEnum ParseOrDefault<TEnum>(string value, bool ignoreCase = false, TEnum defaultValue = default(TEnum)) where TEnum : struct, TClass // value type constraint S depending on T
    {
        if (string.IsNullOrEmpty(value)) { return defaultValue; }
        TEnum result;
        if (Enum.TryParse(value, ignoreCase, out result)) { return result; }
        return defaultValue;
    }
}

public class EnumUtils: ConstrainedEnumParser<System.Enum>
// reference type constraint to any <System.Enum>
{
    // call to parse will then contain constraint to specific <System.Enum>-class
}

उपयोग के उदाहरण:

WeekDay parsedDayOrArgumentException = EnumUtils.Parse<WeekDay>("monday", ignoreCase:true);
WeekDay parsedDayOrDefault;
bool didParse = EnumUtils.TryParse<WeekDay>("clubs", out parsedDayOrDefault, ignoreCase:true);
parsedDayOrDefault = EnumUtils.ParseOrDefault<WeekDay>("friday", ignoreCase:true, defaultValue:WeekDay.Sunday);

पुराना

टिप्पणियों और 'नए' विकास का उपयोग करके share पर मेरे पुराने सुधार:

  • उपयोगकर्ताओं के लिए स्पष्टता के लिए TEnum उपयोग करें
  • अतिरिक्त बाधा-जांच के लिए अधिक इंटरफ़ेस-बाधाएं जोड़ें
  • TryParse हैंडल को ignoreCase करें मौजूदा पैरामीटर के साथ (VS2010 / .Net 4 में पेश किया गया)
  • वैकल्पिक default से जेनेरिक default मान का उपयोग करें (VS2005 / .Net 2 में पेश किया गया)
  • डिफ़ॉल्ट मानों के साथ वैकल्पिक तर्कों (VS2010 / .Net 4 में प्रस्तुत) का उपयोग करें, डिफ़ॉल्ट के लिए, ignoreCase और ignoreCase

जिसके परिणामस्वरूप:

public static class EnumUtils
{
    public static TEnum ParseEnum<TEnum>(this string value,
                                         bool ignoreCase = true,
                                         TEnum defaultValue = default(TEnum))
        where TEnum : struct,  IComparable, IFormattable, IConvertible
    {
        if ( ! typeof(TEnum).IsEnum) { throw new ArgumentException("TEnum must be an enumerated type"); }
        if (string.IsNullOrEmpty(value)) { return defaultValue; }
        TEnum lResult;
        if (Enum.TryParse(value, ignoreCase, out lResult)) { return lResult; }
        return defaultValue;
    }
}

आप कक्षा के लिए एक स्थिर कंस्ट्रक्टर को परिभाषित कर सकते हैं जो जांच करेगा कि टाइप टी एक enum है और अगर यह नहीं है तो अपवाद फेंक दें। जेफरी रिक्टर ने सीएलआर के माध्यम से अपनी पुस्तक सीएलआर में यह विधि दी है।

internal sealed class GenericTypeThatRequiresAnEnum<T> {
    static GenericTypeThatRequiresAnEnum() {
        if (!typeof(T).IsEnum) {
        throw new ArgumentException("T must be an enumerated type");
        }
    }
}

फिर पार्स विधि में, आप स्ट्रिंग से enum में कनवर्ट करने के लिए Enum.Parse (टाइपोफ़ (टी), इनपुट, सत्य) का उपयोग कर सकते हैं। अंतिम वास्तविक पैरामीटर इनपुट के मामले को अनदेखा करने के लिए है।


मुझे हमेशा यह पसंद आया (आप उचित के रूप में संशोधित कर सकते हैं):

public static IEnumerable<TEnum> GetEnumValues()
{
  Type enumType = typeof(TEnum);

  if(!enumType.IsEnum)
    throw new ArgumentException("Type argument must be Enum type");

  Array enumValues = Enum.GetValues(enumType);
  return enumValues.Cast<TEnum>();
}

यदि बाद में प्रत्यक्ष कास्टिंग का उपयोग करना ठीक है, तो मुझे लगता है कि आप जहां भी आवश्यक हो, अपनी विधि में System.Enum बेस क्लास का उपयोग कर सकते हैं। आपको बस टाइप पैरामीटर को ध्यान से बदलने की जरूरत है। तो विधि कार्यान्वयन इस प्रकार होगा:

public static class EnumUtils
{
    public static Enum GetEnumFromString(string value, Enum defaultValue)
    {
        if (string.IsNullOrEmpty(value)) return defaultValue;
        foreach (Enum item in Enum.GetValues(defaultValue.GetType()))
        {
            if (item.ToString().ToLower().Equals(value.Trim().ToLower())) return item;
        }
        return defaultValue;
    }
}

फिर आप इसका उपयोग कर सकते हैं:

var parsedOutput = (YourEnum)EnumUtils.GetEnumFromString(someString, YourEnum.DefaultValue);

चूंकि IConvertible प्रकार IConvertible इंटरफ़ेस लागू IConvertible है, इसलिए बेहतर कार्यान्वयन ऐसा कुछ होना चाहिए:

public T GetEnumFromString<T>(string value) where T : struct, IConvertible
{
   if (!typeof(T).IsEnum) 
   {
      throw new ArgumentException("T must be an enumerated type");
   }

   //...
}

यह अभी भी IConvertible लागू करने वाले मूल्य प्रकारों को पारित करने की अनुमति IConvertible । हालांकि संभावना दुर्लभ हैं।


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

उद्धरण के लिए:

... दोनों बाधाएं वास्तव में वैध आईएल उत्पन्न करती हैं और यदि किसी अन्य भाषा में लिखी जाती हैं तो भी सी # द्वारा उपभोग की जा सकती है (आप प्रबंधित सी ++ या आईएल में उन बाधाओं को घोषित कर सकते हैं)।

कौन जाने


जैसा कि पहले अन्य उत्तरों में कहा गया है; जबकि इसे स्रोत-कोड में व्यक्त नहीं किया जा सकता है, यह वास्तव में आईएल स्तर पर किया जा सकता है। @ क्रिस्टोफर Currens answer दिखाता है कि आईएल कैसे करता है।

Fody एस एड-इन ExtraConstraints.Fody के साथ। यह हासिल करने के लिए, बिल्ड-टूलींग के साथ पूरा करने का एक बहुत ही आसान तरीका है। बस अपनी परियोजना में अपने न्यूजेट पैकेज ( Fody , ExtraConstraints.Fody Fody ) जोड़ें और निम्नानुसार बाधाएं जोड़ें (एक्स्ट्रा कॉन्स्ट्रेनेंट्स के रीडमे से उद्धरण):

public void MethodWithEnumConstraint<[EnumConstraint] T>() {...}

public void MethodWithTypeEnumConstraint<[EnumConstraint(typeof(ConsoleColor))] T>() {...}

और फोडी उपस्थित होने के लिए आवश्यक आईएल जोड़ देगा। प्रतिनिधियों को बाधित करने की अतिरिक्त सुविधा भी ध्यान दें:

public void MethodWithDelegateConstraint<[DelegateConstraint] T> ()
{...}

public void MethodWithTypeDelegateConstraint<[DelegateConstraint(typeof(Func<int>))] T> ()
{...}

Enums के बारे में, आप भी अत्यधिक दिलचस्प Enums.NET नोट करना चाह सकते हैं।


मैंने dimarzionist द्वारा नमूना संशोधित किया। यह संस्करण केवल Enums के साथ काम करेगा और structs के माध्यम से जाने नहीं देंगे।

public static T ParseEnum<T>(string enumString)
    where T : struct // enum 
    {
    if (String.IsNullOrEmpty(enumString) || !typeof(T).IsEnum)
       throw new Exception("Type given must be an Enum");
    try
    {

       return (T)Enum.Parse(typeof(T), enumString, true);
    }
    catch (Exception ex)
    {
       return default(T);
    }
}






enums