it-swarm-tr.com

T bir numaralandırmaya sınırlayan genel yöntem oluşturma

Enum.Parse kavramını genişletmek için bir işlev inşa ediyorum

  • Bir Enum değerinin bulunamaması durumunda varsayılan bir değerin ayrıştırılmasına izin verir
  • Küçük harf duyarsız mı

Bu yüzden aşağıdakileri yazdım:

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

Hata Kısıtlaması alıyorum, özel sınıf System.Enum sınıfı olamaz.

Yeterince adil, ancak Genel Enum'a izin verecek bir geçici çözüm var mı, yoksa Parse işlevini taklit etmek ve çirkin boks gereksinimini kodunuza zorlayan bir özellik olarak bir tür iletmek zorunda kalacağım.

EDIT Aşağıdaki tüm öneriler çok takdir edilmiştir, teşekkürler.

Yerleştim (büyük/küçük harf duyarsızlığını korumak için döngüden ayrıldım - bunu XML ayrıştırırken kullanıyorum)

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 Şubat 2015) Julien Lebosquain kısa bir süre önce MSIL veya F # 'da bir derleyici tarafından uygulanan türde güvenli jenerik bir çözüm yayınladı , iyi bir bakış ve bir değer. Çözüm sayfayı daha da yukarı kabarcıklarsa bu düzenlemeyi kaldıracağım.

1059
johnc

Enum Type IConvertible arabirimini uyguladığından, daha iyi bir uygulama şöyle olmalıdır:

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

   //...
}

Bu, IConvertible öğesini uygulayan değer türlerinin geçmesine izin verecektir. Şansları nadir de olsa.

935
Vivek

Bu özellik nihayet C # 7.3 ile desteklenir!

Aşağıdaki kod parçası (from dotnet örnekleri ) nasıl olduğunu gösterir:

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

C # projenizdeki dil sürümünü 7.3 sürümüne ayarladığınızdan emin olun.


Orijinal cevap aşağıda:

Oyuna geç kaldım, ancak nasıl yapılabileceğini görmek için bir meydan okuma olarak kabul ettim. C # (veya VB.NET'te mümkün değildir, ancak F # için aşağı kaydır), ancak MSIL'de mümkündür . Bu küçük şeyi yazdım ....

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

C = geçerliyse, gibi görünen bir işlev oluşturur.

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

Sonra aşağıdaki C # koduyla:

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
}

Ne yazık ki bu, kodunuzun bu bölümünü C # yerine MSIL ile yazılmış olması anlamına gelir; tek ek avantajı bu yöntemi System.Enum ile sınırlayabilmenizdir. Aynı zamanda bir serseri. Çünkü ayrı bir Meclis'e derlendi. Ancak, bu şekilde dağıtmanız gerektiği anlamına gelmez.

.Assembly MyThing{} satırını kaldırarak ve ilasmı şu şekilde çağırarak:

ilasm.exe /DLL /OUTPUT=MyThing.netmodule

meclis yerine bir netmodül olsun.

Ne yazık ki, VS2010 (ve daha önce açık bir şekilde) netmodule referansları eklemeyi desteklemiyor, bu da hata ayıklama sırasında 2 ayrı montajda bırakmanız gerektiği anlamına geliyor. Bunları Meclisinizin bir parçası olarak eklemenin tek yolu csc.exe dosyasını /addmodule:{files} komut satırı argümanını kullanarak çalıştırmaktır. Bir MSBuild betiğinde de ağrılı olmazdı. Tabii ki, eğer cesur ya da aptalsanız, her seferinde kendiniz el ile csc çalıştırabilirsiniz. Ve çok sayıda meclisin buna erişmesi gerektiğinden kesinlikle daha da karmaşık bir hal alıyor.

Yani, net yapılabilir. Ekstra çabaya değer mi? Şey, sanırım buna karar vermene izin vereceğim.


F # alternatif olarak çözüm

Ekstra Kredi: MSIL: F # dışında en az bir .NET dilinde enum üzerinde genel bir kısıtlamanın mümkün olduğu ortaya çıktı.

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

Bu, Visual Studio IDE desteği ile iyi bilinen bir dil olduğundan, bakımı kolaydır, ancak bunun için çözümünüzde ayrı bir projeye ihtiyacınız vardır. Bununla birlikte, doğal olarak önemli ölçüde farklı IL üretir (kod çok farklıdır) ve diğer herhangi bir dış kütüphanede olduğu gibi, diğer herhangi bir dış kütüphanede de olması gereken FSharp.Core kütüphanesine dayanır. dağılımı.

İşte (temel olarak MSIL çözümüyle aynı) nasıl kullanabileceğinizi ve başka türlü eşanlamlı yapılarda doğru şekilde başarısız olduğunu göstermek için:

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

C # 7.3 ile başlayarak (Visual Studio 2017 ≥ v15.7 ile kullanılabilir), bu kod şimdi tamamen geçerlidir:

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

C # ≤ 7.2

Kısıt devralma kötüye kullanarak gerçek bir derleyici zorla enum kısıtlama olabilir. Aşağıdaki kod hem bir class hem de bir struct sınırlamasını aynı anda belirtir:

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

Kullanımı:

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

Not: Bu özellikle C # 5.0 dil spesifikasyonunda belirtilmiştir:

S tipi parametresi, T tipi parametresine bağlıysa: [...] S'nin değer tipi kısıtlamasına sahip olması ve T'nin referans tipi kısıtlamasına sahip olması geçerlidir. Bu, T'yi, System.Object, System.ValueType, System.Enum ve herhangi bir arabirim türüyle sınırlar.

186
Julien Lebosquain

Düzen

Şimdi soru mükemmel bir şekilde --- Lebosquain tarafından cevaplandı. Ayrıca cevabını ignoreCasename__, defaultValueve isteğe bağlı argümanlarla genişletmek istiyorum, ayrıca TryParseve ParseOrDefaulteklerken.

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
}

Kullanım örnekleri:

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

Eski

Eski geliştirmelerim Vivek'in cevabı yorumları ve 'yeni' gelişmeleri kullanarak:

  • kullanıcılar için netlik sağlamak için TEnumkullanın
  • ek kısıtlama kontrolü için daha fazla arayüz kısıtlaması ekleyin
  • let TryParseNAME _ varolan parametreyle ignoreCaseişle (VS2010/.Net 4'te tanıtıldı)
  • isteğe bağlı olarak jenerik defaultvalue (VS2005/.Net 2'de tanıtıldı) kullanın.
  • use isteğe bağlı argümanlar (VS2010/.Net 4'te tanıtıldı), defaultValueve ignoreCaseiçin varsayılan değerlerle

sonuçlanan:

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

Sınıf için T türünün bir enum olduğunu kontrol edecek ve değilse bir istisna atan bir statik kurucu tanımlayabilirsiniz. Jeffery Richter tarafından CLR adlı kitabında C # ile belirtilen yöntem budur.

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

Daha sonra ayrıştırma yönteminde, string'den enum'a dönüştürmek için Enum.Parse (typeof (typeof (T), input, true)) komutunu kullanabilirsiniz. Son gerçek parametre, girişin yok sayılması içindir.

18
Karg

Ayrıca, Enum kısıtlamaları kullanılarak C # 7.3 piyasaya sürüldüğünden, ek kontroller ve şeyler yapmak zorunda kalmadan kutunun dışında desteklendiği göz önünde bulundurulmalıdır.

Bu yüzden ileriye gidiyor ve projenizin dil sürümünü C # 7.3 olarak değiştirdiyseniz, aşağıdaki kod kusursuz bir şekilde çalışıyor:

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

Dil versiyonunu C # 7.3 olarak nasıl değiştireceğinizi bilmiyorsanız aşağıdaki ekran görüntüsüne bakınız: enter image description here

EDIT 1 - Gerekli Visual Studio Sürümü ve ReSharper'ı dikkate alarak

Visual Studio'nun yeni sözdizimini tanıması için en az 15.7 sürümüne ihtiyacınız var. Microsoft'un sürüm notlarında da belirtilenleri bulabilirsiniz, bkz Visual Studio 2017 15.7 Sürüm Notları . Bu geçerli soruyu belirttiğiniz için @MohamedElshawaf teşekkür ederiz.

Pls ayrıca, benim durumumda ReSharper 2018.1’in bu EDIT’i yazarken henüz C # 7.3’ü desteklemediğini unutmayın. ReSharper'ın aktif hale getirilmesi, Enum kısıtlamasını bana'System.Array', 'System.Delegate', 'System.Enum', 'System.ValueType', 'object' türlerini parametre kısıtlaması olarak kullanmamayı işaret ediyor.. ReSharper'Enum' kısıtlamasınınmetodunun T parametresi sınırlamasını kaldırması için hızlı bir düzeltme olarak önerir.

Ancak,Araçlar -> Seçenekler -> ReSharper Ultimate -> Genelaltında ReSharper’ı geçici olarak kapatırsanız, VS 15.7 veya daha yüksek ve C # 7.3 kullanmanız durumunda sözdiziminin tamamen iyi olduğunu göreceksiniz. veya daha yüksek.

13
baumgarb

Dimarzionist tarafından örneği değiştirdim. Bu sürüm sadece Enums ile çalışacak ve yapıların geçmesine izin vermeyecektir.

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

Kodu biraz geliştirmeye çalıştım:

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

Enum'u enum değeriyle ilişkilendirilmiş metinle kullanmam gereken belirli bir şartım var. Örneğin, hata türünü belirtmek için enum kullandığımda, hata ayrıntılarını açıklamak gerekir.

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

Umarım bu yardımcı olur:

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

Bu benim işim. Cevaplardan ve MSDN'den birleştirildi

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

MSDN Source

3
KarmaEDV

İlginçtir ki, görünüşe göre bu diğer dillerde mümkün (Yönetilen C++, IL doğrudan).

Alıntılamak:

... Her iki kısıtlama da aslında geçerli bir IL üretir ve başka bir dilde yazılmışsa C # tarafından da tüketilebilir (bu kısıtlamaları yönetilen C++ veya IL'de ilan edebilirsiniz).

Kim bilir

3
Andrew Backer

Mevcut cevaplar C # <= 7.2 itibariyle doğrudur. Bununla birlikte, aşağıdakilere izin vermek için bir C # dili özellik isteği (bir corefx özellik isteği) vardır;

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

Yazma sırasında, özellik Dil Gelişimi Toplantılarında "Tartışma" dır.

DÜZENLE

nawfal 'nin bilgisine göre, bu C # 7. ' de tanıtılmaktadır.

3
DiskJunky

Vivek'in çözümünü tekrar kullanabileceğiniz bir hizmet sınıfına yerleştirdim. Lütfen, türünüzde hala "sınırlamalar: T: struct, IConvertible" türlerini tanımlamanız gerektiğini unutmayın.

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

Bunu her zaman sevdim (uygun şekilde değiştirebilirsiniz):

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

Daha önce diğer cevaplarda belirtildiği gibi; Bu kaynak kodda ifade edilemezken, aslında IL Seviyesinde yapılabilir. @Christopher Currens answer IL'nin buna nasıl yaptığını gösterir.

Fody s Eklentisi ExtraConstraints.Fody ile bunu başarmak için derleme oluşturma ile tamamlanan çok basit bir yol var. Sadece nuget paketlerini (Fody, ExtraConstraints.Fody) projenize ekleyin ve kısıtlamaları aşağıdaki gibi ekleyin (ExtraConstraints'in Benioku Belgesi):

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

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

ve Fody, kısıtlamanın mevcut olması için gerekli IL'yi ekleyecektir. Ayrıca delegelerin kısıtlanmasının ek özelliğine dikkat edin:

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

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

Enums ile ilgili olarak, son derece ilginç olan Enums.NET notunu da almak isteyebilirsiniz.

1

Metot uygulamasını incelemek için bir yöntem Metot to get integer value from enum oluşturdum

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

bu kullanım

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

Christopher Currens'in IL'yi kullanarak çözümünü sevdim, ancak MSIL'i yapım sürecine dahil etmek konusunda zor işlerle uğraşmak istemeyenler için, C # 'da benzer işlevler yazdım.

Enum özel tip olduğu için where T : Enum gibi genel kısıtlamaları kullanamayacağınızı unutmayın. Bu nedenle verilen jenerik tipin gerçekten enum olup olmadığını kontrol etmeliyim.

Benim işim:

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

Daha sonra doğrudan döküm kullanmak uygunsa, yönteminizde System.Enum base sınıfını kullanabilirsiniz, nerede olursanız olun. Sadece tip parametrelerini dikkatlice değiştirmeniz gerekir. Dolayısıyla yöntem uygulaması şöyle olacaktır:

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

Sonra gibi kullanabilirsiniz:

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