c# - पटन - बिहार एएनएम नर्सिंग patna, bihar




एक एनम के लिए टी बाध्यकारी जेनेरिक विधि बनाएँ (12)

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


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

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

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


आप बाधा विरासत का दुरुपयोग करके एक असली संकलक लागू 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 भाषा विनिर्देश में कहा गया है:

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


चूंकि 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 नोट करना चाह सकते हैं।


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

कृपया ध्यान दें कि आप जेनेरिक प्रतिबंध का उपयोग नहीं कर सकते हैं जैसे 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;
}

मुझे खेल के लिए देर हो चुकी है, लेकिन मैंने यह देखने के लिए एक चुनौती के रूप में लिया कि यह कैसे किया जा सकता है। सी # (या वीबी.नेट में यह संभव नहीं है, लेकिन एफ # के लिए नीचे स्क्रॉल करें), लेकिन एमएसआईएल में संभव है। मैंने यह छोटा लिखा .... चीज़

// license: http://www.apache.org/licenses/LICENSE-2.0.html
.assembly MyThing{}
.class public abstract sealed MyThing.Thing
       extends [mscorlib]System.Object
{
  .method public static !!T  GetEnumFromString<valuetype .ctor ([mscorlib]System.Enum) T>(string strValue,
                                                                                          !!T defaultValue) cil managed
  {
    .maxstack  2
    .locals init ([0] !!T temp,
                  [1] !!T return_value,
                  [2] class [mscorlib]System.Collections.IEnumerator enumerator,
                  [3] class [mscorlib]System.IDisposable disposer)
    // if(string.IsNullOrEmpty(strValue)) return defaultValue;
    ldarg strValue
    call bool [mscorlib]System.String::IsNullOrEmpty(string)
    brfalse.s HASVALUE
    br RETURNDEF         // return default it empty

    // foreach (T item in Enum.GetValues(typeof(T)))
  HASVALUE:
    // Enum.GetValues.GetEnumerator()
    ldtoken !!T
    call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
    call class [mscorlib]System.Array [mscorlib]System.Enum::GetValues(class [mscorlib]System.Type)
    callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Array::GetEnumerator() 
    stloc enumerator
    .try
    {
      CONDITION:
        ldloc enumerator
        callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
        brfalse.s LEAVE

      STATEMENTS:
        // T item = (T)Enumerator.Current
        ldloc enumerator
        callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
        unbox.any !!T
        stloc temp
        ldloca.s temp
        constrained. !!T

        // if (item.ToString().ToLower().Equals(value.Trim().ToLower())) return item;
        callvirt instance string [mscorlib]System.Object::ToString()
        callvirt instance string [mscorlib]System.String::ToLower()
        ldarg strValue
        callvirt instance string [mscorlib]System.String::Trim()
        callvirt instance string [mscorlib]System.String::ToLower()
        callvirt instance bool [mscorlib]System.String::Equals(string)
        brfalse.s CONDITION
        ldloc temp
        stloc return_value
        leave.s RETURNVAL

      LEAVE:
        leave.s RETURNDEF
    }
    finally
    {
        // ArrayList's Enumerator may or may not inherit from IDisposable
        ldloc enumerator
        isinst [mscorlib]System.IDisposable
        stloc.s disposer
        ldloc.s disposer
        ldnull
        ceq
        brtrue.s LEAVEFINALLY
        ldloc.s disposer
        callvirt instance void [mscorlib]System.IDisposable::Dispose()
      LEAVEFINALLY:
        endfinally
    }

  RETURNDEF:
    ldarg defaultValue
    stloc return_value

  RETURNVAL:
    ldloc return_value
    ret
  }
} 

जो एक ऐसा फ़ंक्शन उत्पन्न करता है जो इस तरह दिखेगा, अगर यह वैध सी #:

T GetEnumFromString<T>(string valueString, T defaultValue) where T : Enum

फिर निम्नलिखित सी # कोड के साथ:

using MyThing;
// stuff...
private enum MyEnum { Yes, No, Okay }
static void Main(string[] args)
{
    Thing.GetEnumFromString("No", MyEnum.Yes); // returns MyEnum.No
    Thing.GetEnumFromString("Invalid", MyEnum.Okay);  // returns MyEnum.Okay
    Thing.GetEnumFromString("AnotherInvalid", 0); // compiler error, not an Enum
}

दुर्भाग्यवश, इसका मतलब है कि आपके कोड का यह हिस्सा सी # के बजाय एमएसआईएल में लिखा गया है, केवल एक ही अतिरिक्त लाभ यह है कि आप इस विधि को System.Enum द्वारा बाधित करने में सक्षम हैं। यह एक बमर भी है, क्योंकि यह एक अलग असेंबली में संकलित हो जाता है। हालांकि, इसका मतलब यह नहीं है कि आपको इसे इस तरह से तैनात करना है।

लाइन को हटाकर .assembly MyThing{} और .assembly MyThing{} का आह्वान निम्नानुसार है:

ilasm.exe /DLL /OUTPUT=MyThing.netmodule

आपको एक असेंबली के बजाय नेटमॉड्यूल मिलता है।

दुर्भाग्यवश, वीएस -2010 (और इससे पहले, स्पष्ट रूप से) netmodule संदर्भ जोड़ने का समर्थन नहीं करता है, जिसका अर्थ है कि जब आप डिबगिंग करते हैं तो आपको इसे 2 अलग-अलग असेंबली में छोड़ना होगा। आपके असेंबली के हिस्से के रूप में उन्हें जोड़ने का एकमात्र तरीका यह होगा कि /addmodule:{files} smodule /addmodule:{files} कमांड लाइन तर्क का उपयोग करके csc.exe को स्वयं चलाएं। यह एक एमएसबील्ड लिपि में बहुत दर्दनाक नहीं होगा। बेशक, यदि आप बहादुर या बेवकूफ हैं, तो आप प्रत्येक बार मैन्युअल रूप से सीएससी चला सकते हैं। और यह निश्चित रूप से अधिक जटिल हो जाता है क्योंकि एकाधिक असेंबली को इसकी आवश्यकता होती है।

तो, यह नेट में किया जा सकता है। क्या यह अतिरिक्त प्रयास लायक है? उम, ठीक है, मुझे लगता है कि मैं आपको उस पर फैसला करने दूँगा।

विकल्प के रूप में एफ # समाधान

अतिरिक्त क्रेडिट: यह पता चला है कि एमएसआईएल के अलावा कम से कम एक अन्य .NET भाषा में enum पर एक सामान्य प्रतिबंध संभव है: एफ #।

type MyThing =
    static member GetEnumFromString<'T when 'T :> Enum> str defaultValue: 'T =
        /// protect for null (only required in interop with C#)
        let str = if isNull str then String.Empty else str

        Enum.GetValues(typedefof<'T>)
        |> Seq.cast<_>
        |> Seq.tryFind(fun v -> String.Compare(v.ToString(), str.Trim(), true) = 0)
        |> function Some x -> x | None -> defaultValue

यह एक आसान बनाए रखना आसान है क्योंकि यह पूर्ण विजुअल स्टूडियो आईडीई समर्थन के साथ एक प्रसिद्ध भाषा है, लेकिन इसके लिए आपको अभी भी अपने समाधान में एक अलग परियोजना की आवश्यकता है। हालांकि, यह स्वाभाविक रूप से काफी अलग आईएल उत्पन्न करता है (कोड बहुत अलग है) और यह FSharp.Core लाइब्रेरी पर निर्भर करता है, जो कि किसी अन्य बाहरी पुस्तकालय की तरह ही आपके वितरण का हिस्सा बनने की आवश्यकता है।

यहां बताया गया है कि आप इसका उपयोग कैसे कर सकते हैं (मूल रूप से एमएसआईएल समाधान के समान), और यह दिखाने के लिए कि यह अन्यथा समानार्थी structs पर सही ढंग से विफल रहता है:

// works, result is inferred to have type StringComparison
var result = MyThing.GetEnumFromString("OrdinalIgnoreCase", StringComparison.Ordinal);
// type restriction is recognized by C#, this fails at compile time
var result = MyThing.GetEnumFromString("OrdinalIgnoreCase", 42);

मेरे पास विशिष्ट आवश्यकता है जहां मुझे enum मान से जुड़े पाठ के साथ enum का उपयोग करने की आवश्यकता है। उदाहरण के लिए जब मैं त्रुटि प्रकार निर्दिष्ट करने के लिए enum का उपयोग करता हूं तो इसे त्रुटि विवरणों का वर्णन करने के लिए आवश्यक होता है।

public static class XmlEnumExtension
{
    public static string ReadXmlEnumAttribute(this Enum value)
    {
        if (value == null) throw new ArgumentNullException("value");
        var attribs = (XmlEnumAttribute[]) value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof (XmlEnumAttribute), true);
        return attribs.Length > 0 ? attribs[0].Name : value.ToString();
    }

    public static T ParseXmlEnumAttribute<T>(this string str)
    {
        foreach (T item in Enum.GetValues(typeof(T)))
        {
            var attribs = (XmlEnumAttribute[])item.GetType().GetField(item.ToString()).GetCustomAttributes(typeof(XmlEnumAttribute), true);
            if(attribs.Length > 0 && attribs[0].Name.Equals(str)) return item;
        }
        return (T)Enum.Parse(typeof(T), str, true);
    }
}

public enum MyEnum
{
    [XmlEnum("First Value")]
    One,
    [XmlEnum("Second Value")]
    Two,
    Three
}

 static void Main()
 {
    // Parsing from XmlEnum attribute
    var str = "Second Value";
    var me = str.ParseXmlEnumAttribute<MyEnum>();
    System.Console.WriteLine(me.ReadXmlEnumAttribute());
    // Parsing without XmlEnum
    str = "Three";
    me = str.ParseXmlEnumAttribute<MyEnum>();
    System.Console.WriteLine(me.ReadXmlEnumAttribute());
    me = MyEnum.One;
    System.Console.WriteLine(me.ReadXmlEnumAttribute());
}

मैंने 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);
    }
}

मैंने विधि कार्यान्वयन को देखने के लिए 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

मैंने विवेक के समाधान को एक उपयोगिता वर्ग में encapsulated है जिसे आप पुन: उपयोग कर सकते हैं। कृपया ध्यान दें कि आपको अभी भी टाइप प्रकार की बाधाओं को परिभाषित करना चाहिए "जहां टी: स्ट्रक्चर, आईकोनवर्टिबल" आपके प्रकार पर है।

using System;

internal static class EnumEnforcer
{
    /// <summary>
    /// Makes sure that generic input parameter is of an enumerated type.
    /// </summary>
    /// <typeparam name="T">Type that should be checked.</typeparam>
    /// <param name="typeParameterName">Name of the type parameter.</param>
    /// <param name="methodName">Name of the method which accepted the parameter.</param>
    public static void EnforceIsEnum<T>(string typeParameterName, string methodName)
        where T : struct, IConvertible
    {
        if (!typeof(T).IsEnum)
        {
            string message = string.Format(
                "Generic parameter {0} in {1} method forces an enumerated type. Make sure your type parameter {0} is an enum.",
                typeParameterName,
                methodName);

            throw new ArgumentException(message);
        }
    }

    /// <summary>
    /// Makes sure that generic input parameter is of an enumerated type.
    /// </summary>
    /// <typeparam name="T">Type that should be checked.</typeparam>
    /// <param name="typeParameterName">Name of the type parameter.</param>
    /// <param name="methodName">Name of the method which accepted the parameter.</param>
    /// <param name="inputParameterName">Name of the input parameter of this page.</param>
    public static void EnforceIsEnum<T>(string typeParameterName, string methodName, string inputParameterName)
        where T : struct, IConvertible
    {
        if (!typeof(T).IsEnum)
        {
            string message = string.Format(
                "Generic parameter {0} in {1} method forces an enumerated type. Make sure your input parameter {2} is of correct type.",
                typeParameterName,
                methodName,
                inputParameterName);

            throw new ArgumentException(message);
        }
    }

    /// <summary>
    /// Makes sure that generic input parameter is of an enumerated type.
    /// </summary>
    /// <typeparam name="T">Type that should be checked.</typeparam>
    /// <param name="exceptionMessage">Message to show in case T is not an enum.</param>
    public static void EnforceIsEnum<T>(string exceptionMessage)
        where T : struct, IConvertible
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException(exceptionMessage);
        }
    }
}

यदि बाद में प्रत्यक्ष कास्टिंग का उपयोग करना ठीक है, तो मुझे लगता है कि आप जहां भी आवश्यक हो, अपनी विधि में 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);

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

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

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







enums