it-swarm-eu.dev

Vytvořit obecnou metodu omezující T na Enum

Stavím funkci, která rozšíří koncept Enum.Parse

  • Umožňuje výchozí hodnotu analyzovat v případě, že hodnota Enum nebyla nalezena
  • Nerozlišuje velikost písmen

Tak jsem napsal následující:

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

Dostávám chybu Chyba nemůže být speciální třída System.Enum.

Dostatečné, ale existuje nějaké řešení, které by umožnilo generický Enum, nebo budu muset napodobovat funkci Parse a předávat typ jako atribut, který nutí ošklivý požadavek na box do vašeho kódu.

EDIT Všechny níže uvedené návrhy byly velmi oceněny, díky.

Usadili se (opustil jsem smyčku, abych zachoval necitlivost na případy - používám to při analýze XML)

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

EDIT: (16. února 2015) Julien Lebosquain nedávno přidal překladač vynucuje typové generické řešení v MSIL nebo F # níže , což je dobře stojí za to podívat, a upvote. Tuto úpravu odstraním, pokud řešení bubliny dále zvětší stránku.

1059
johnc

Protože Enum Typ implements IConvertible rozhraní, lepší implementace by měla být něco takového:

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

   //...
}

Toto bude stále povolit předávání typů hodnot implementujících IConvertible. Šance jsou však vzácné.

935
Vivek

Tato funkce je nakonec podporována v C # 7.3!

Následující úryvek (od kázky dotnet ) ukazuje, jak:

public static Dictionary<int, string> EnumNamedValues<T>() where T : System.Enum
{
    var result = new Dictionary<int, string>();
    var values = Enum.GetValues(typeof(T));

    foreach (int item in values)
        result.Add(item, Enum.GetName(typeof(T), item));
    return result;
}

Nezapomeňte nastavit jazykovou verzi v projektu C # na verzi 7.3.


Původní odpověď níže:

Jsem pozdě na hru, ale vzal jsem to jako výzvu, abych zjistil, jak by se to mohlo udělat. Není to možné v C # (nebo VB.NET, ale posuňte se dolů pro F #), ale je možné v MSIL. Napsal jsem tuhle malou věc

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

Který generuje funkci, která by vypadala takto, kdyby byla platná C #:

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

Pak s následujícím kódem C #:

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
}

Bohužel to znamená mít tuto část vašeho kódu napsanou v MSIL namísto C #, s jedinou přidanou výhodou, že jste schopni tuto metodu omezit pomocí System.Enum. Je to také druh nájemného, ​​protože se sestavuje do samostatného shromáždění. Neznamená to však, že je musíte nasazovat tímto způsobem.

Odstraněním řádku .Assembly MyThing{} a vyvoláním ilasm následujícím způsobem:

ilasm.exe /DLL /OUTPUT=MyThing.netmodule

namísto shromáždění získáte síťový modul.

Bohužel, VS2010 (a dřívější, samozřejmě) nepodporuje přidávání referencí netmodule, což znamená, že budete muset ladit ve dvou samostatných sestavách. Jediný způsob, jak je přidat jako součást svého shromáždění, by bylo spustit csc.exe sami pomocí argumentu /addmodule:{files}. Nebylo by to příliš bolestivé ve skriptu MSBuild. Samozřejmě, pokud jste stateční nebo hloupí, můžete spustit csc ručně pokaždé. A určitě to bude složitější, protože k němu bude potřebovat více sestav.

Takže to může být provedeno v .Net. Stojí to za další úsilí? Um, no, myslím, že ti dovolím rozhodnout o tom.


F # Řešení jako alternativa

Extra kredit: Ukazuje se, že obecné omezení enum je možné v alespoň jednom dalším jazyce .NET kromě MSIL: F #.

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

Tento je snadnější udržovat, protože je to dobře známý jazyk s plnou podporou Visual Studio IDE, ale ve vašem řešení stále potřebujete samostatný projekt. Přirozeně však produkuje značně odlišné IL (kód je velmi odlišný) a spoléhá se na knihovnu FSharp.Core, která se stejně jako každá jiná externí knihovna musí stát součástí vaší rozdělení.

Zde je návod, jak jej můžete použít (v podstatě stejné jako řešení MSIL) a ukázat, že správně selže na jinak synonymních strukturách:

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

C # ≥ 7.3

Počínaje verzí C # 7.3 (k dispozici v aplikaci Visual Studio 2017 ≥ v15.7) je tento kód nyní zcela platný:

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

C # ≤ 7,2

Skutečný kompilátor může mít vynucené omezení enumu tím, že zneužije dědičnost omezení. Následující kód určuje současně omezení class a 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>
{
}

Používání:

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

Poznámka: Toto je specificky uvedeno ve specifikaci jazyka C # 5.0:

Pokud parametr typu S závisí na parametru typu T, pak: [...] Platí, že S má omezení typu hodnoty a T má omezení referenčního typu. Efektivně tyto limity T na typy System.Object, System.ValueType, System.Enum a jakýkoli typ rozhraní.

186

Upravit

Na otázku nyní skvěle odpověděl Julien Lebosquain . Chtěl bych také rozšířit jeho odpověď o ignoreCasename__, defaultValuea volitelné argumenty, přičemž přidávám TryParsea ParseOrDefaultname__.

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
}

Příklady použití:

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

Staré

Moje stará vylepšení Vivekova odpověď pomocí komentářů a 'nových' vývojů:

  • pro přehlednost použijte TEnumname__
  • přidat další omezení rozhraní pro další kontrolu omezení
  • let TryParseNAME _ popisovač ignoreCases existujícím parametrem (zaveden ve VS2010/.Net 4)
  • volitelně použijte obecnou hodnotu defaultNAME_ (zavedeno ve VS2005/.Net 2)
  • use volitelné argumenty (zavedeno ve VS2010/.Net 4) s výchozími hodnotami, pro defaultValuea ignoreCasename__

což má za následek:

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;
    }
}
30
Yahoo Serious

Pro třídu můžete definovat statický konstruktor, který zkontroluje, zda typ T je výčtem a v případě, že tomu tak není, vyvolá výjimku. Toto je metoda, kterou zmínil Jeffery Richter ve své knize CLR přes C #.

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

Pak v parse metoda, stačí použít Enum.Parse (typeof (T), vstup, true) převést z řetězce na enum. Poslední parametr true je pro ignorování případu vstupu.

18
Karg

Mělo by se také vzít v úvahu, že vzhledem k tomu, že vydání C # 7.3 s použitím omezení Enum je podporováno mimo zařízení, aniž by bylo nutné provádět další kontroly a další funkce.

Takže v budoucnu a vzhledem k tomu, že jste změnili jazykovou verzi svého projektu na C # 7.3, bude následující kód fungovat v pořádku:

    private static T GetEnumFromString<T>(string value, T defaultValue) where T : Enum
    {
        // Your code goes here...
    }

V případě, že nevíte, jak změnit jazykovou verzi na C # 7.3, podívejte se na následující screenshot: enter image description here

EDIT 1 - Požadovaná verze Visual Studio a zvažující ReSharper

Aby Visual Studio rozpoznala novou syntaxi, potřebujete alespoň verzi 15.7. Můžete najít, že také uvedené v poznámkách k vydání společnosti Microsoft, viz Visual Studio 2017 15.7 Poznámky k verzi . Díky @MohamedElshawaf za poukázání na tuto platnou otázku.

Pls také poznamenat, že v mém případě ReSharper 2018.1 od psaní tohoto EDIT ještě nepodporuje C # 7.3. Po aktivaci funkce ReSharper zvýrazní omezení Enum jako chybu, která mi říká Nelze použít 'System.Array', 'System.Delegate', 'System.Enum', 'System.ValueType', 'object' as omezení parametru typu . ReSharper navrhuje jako rychlou opravu Odstranit omezení Enum typu paramter T metody

Pokud však dočasně vypnete ReSharper pod položkou Nástroje -> Možnosti -> ReSharper Ultimate -> Obecné , uvidíte, že syntaxe je naprosto v pořádku, protože používáte VS 15.7 nebo vyšší a C # 7.3 nebo vyšší.

13
baumgarb

Vzorek jsem upravil dimarzionistou. Tato verze bude fungovat pouze s Enums a nenechá strukturu projít.

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

Pokusil jsem se kód trochu vylepšit:

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

Mám specifický požadavek, kdy jsem musel použít enum s textem spojeným s hodnotou enum. Například, když používám enum k určení typu chyby, která je požadována pro popis chybových detailů.

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());
}
5
Sunny Rajwadi

Doufám, že je to užitečné:

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

To je můj názor. Kombinováno z odpovědí a MSDN

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

Zdroj MSDN

3
KarmaEDV

Zajímavé je, že toto je zřejmě možné v jiných langaugech (Managed C++, IL přímo).

Citovat:

... Obě omezení skutečně produkují platné IL a mohou být také spotřebovány C #, pokud jsou napsány v jiném jazyce (tato omezení můžete deklarovat ve spravovaném C++ nebo v IL).

Kdo ví

3
Andrew Backer

Existující odpovědi jsou pravdivé jako u C # <= 7.2. Existuje však jazyk C # požadavek na funkci (vázán na corefx požadavek na funkci), aby bylo možné následující;

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

V době psaní, funkce je "V diskusi" na schůzkách jazykového rozvoje.

UPRAVIT

Jak na nawfal info, toto je představeno v C # 7. .

3
DiskJunky

Zapouzdřila jsem Vivekovo řešení do utility třídy, kterou můžete znovu použít. Mějte prosím na paměti, že byste stále měli definovat typová omezení "kde T: struct, IConvertible" na vašem typu.

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

Vždy se mi to líbilo (můžete upravit podle potřeby):

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>();
}
1
Jeff

Jak již bylo uvedeno v jiných odpovědích; zatímco toto nemůže být vyjádřeno ve zdrojovém kódu to může být vlastně děláno na IL úrovni. @ Christopher Currens odpověď ukazuje, jak k tomu IL přistupuje.

S Fody s Add-In ExtraConstraints.Fody k dosažení tohoto cíle je k dispozici velmi jednoduchý způsob, kompletní s sestavením nástrojů. Stačí přidat své nuget balíčky (Fody, ExtraConstraints.Fody) do vašeho projektu a přidat omezení takto (Výňatek z Readme ExtraConstraints):

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

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

a Fody přidá potřebné IL pro omezení, které má být přítomno. Všimněte si také další funkce omezujících delegátů:

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

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

Pokud jde o Enums, můžete také vzít na vědomí velmi zajímavé Enums.NET .

1

Vytvořil jsem metodu rozšíření to get integer value from enum podívejte se na implementaci metody

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

toto je použití

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

Miloval jsem řešení Christophera Currense pomocí IL, ale pro ty, kteří se nechtějí zabývat složitým podnikáním včetně MSIL do svého procesu sestavení, jsem napsal podobnou funkci v C #.

Všimněte si však, že nelze použít obecné omezení jako where T : Enum, protože Enum je speciální typ. Proto musím zkontrolovat, zda je daný obecný typ skutečně enum.

Moje funkce je:

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

Je-li v pořádku použít přímý casting poté, myslím, že můžete použít metodu System.Enum ve vaší metodě, kdykoliv je to nutné. Musíte pouze pečlivě vyměnit parametry typu. Implementace metody by tedy byla:

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

Pak jej můžete použít jako:

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