String reprezentacja Enum

Mam następujące wyliczenie:

public enum AuthenticationMethod
{
    FORMS = 1,
    WINDOWSAUTHENTICATION = 2,
    SINGLESIGNON = 3
}

Problem polega jednak na tym, że potrzebuję słowa "formy", gdy proszę o uwierzytelnienie.Formularze, a nie id 1.

Znalazłem następujące rozwiązanie tego problemu ( link):

Najpierw muszę utworzyć własny atrybut o nazwie "StringValue":

public class StringValue : System.Attribute
{
    private readonly string _value;

    public StringValue(string value)
    {
        _value = value;
    }

    public string Value
    {
        get { return _value; }
    }

}

Wtedy mogę dodać ten atrybut do mojego enumeratora:

public enum AuthenticationMethod
{
    [StringValue("FORMS")]
    FORMS = 1,
    [StringValue("WINDOWS")]
    WINDOWSAUTHENTICATION = 2,
    [StringValue("SSO")]
    SINGLESIGNON = 3
}

I oczywiście potrzebuję czegoś, żeby to odzyskać StringValue:

public static class StringEnum
{
    public static string GetStringValue(Enum value)
    {
        string output = null;
        Type type = value.GetType();

        //Check first in our cached results...

        //Look for our 'StringValueAttribute' 

        //in the field's custom attributes

        FieldInfo fi = type.GetField(value.ToString());
        StringValue[] attrs =
           fi.GetCustomAttributes(typeof(StringValue),
                                   false) as StringValue[];
        if (attrs.Length > 0)
        {
            output = attrs[0].Value;
        }

        return output;
    }
}

Dobrze, teraz mam narzędzia, aby uzyskać wartość ciągu Dla enumeratora. Mogę wtedy użyć go w ten sposób:

string valueOfAuthenticationMethod = StringEnum.GetStringValue(AuthenticationMethod.FORMS);
/ Align = "left" / Zastanawiałem się, czy jest na to lepsze rozwiązanie.

Próbowałem też czegoś ze słownikiem i właściwościami statycznymi, ale to też nie było lepsze.

 843
Author: Nisarg Shah, 0000-00-00

7 answers

Trytype-safe-enum pattern.

public sealed class AuthenticationMethod {

    private readonly String name;
    private readonly int value;

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (1, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (2, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (3, "SSN");        

    private AuthenticationMethod(int value, String name){
        this.name = name;
        this.value = value;
    }

    public override String ToString(){
        return name;
    }

}

Update Jawna (lub niejawna) konwersja typu może być wykonana przez

  • Dodawanie pola statycznego z mapowaniem

    private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>();
    
    • N. b. aby inicjalizacja pól " enum member "nie powodowała wystąpienia Nullreferencexception podczas wywoływania konstruktora instancji, należy umieścić pole słownika przed polami" enum member " w swojej klasie. Dzieje się tak dlatego, że inicjalizatory pola statycznego wywołane są w kolejności deklaracji, a przed konstruktorem statycznym, tworząc dziwną i konieczną, ale mylącą sytuację, w której konstruktor instancji może być wywołany przed zainicjalizowaniem wszystkich pól statycznych i przed wywołaniem konstruktora statycznego.
  • Wypełnianie tego mapowania w konstruktorze instancji

    instance[name] = this;
    
  • Oraz dodanie operatora konwersji typu zdefiniowanego przez użytkownika

    public static explicit operator AuthenticationMethod(string str)
    {
        AuthenticationMethod result;
        if (instance.TryGetValue(str, out result))
            return result;
        else
            throw new InvalidCastException();
    }
    
 821
Author: Jakub Šturc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-12 08:25:53

Użyj metody

Enum.GetName(Type MyEnumType,  object enumvariable)  

Jak w (Załóżmy, że Shipper jest zdefiniowanym Enum)

Shipper x = Shipper.FederalExpress;
string s = Enum.GetName(typeof(Shipper), x);

Jest kilka innych statycznych metod na klasie Enum, które warto zbadać...

 211
Author: Charles Bretana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-28 14:33:40

Możesz odwoływać się do nazwy, a nie do wartości, używając ToString ()

Console.WriteLine("Auth method: {0}", AuthenticationMethod.Forms.ToString());

Dokumentacja jest tutaj:

Http://msdn.microsoft.com/en-us/library/16c1xs4z.aspx

...a jeśli nazwiesz swoje enums w przypadku Pascala (tak jak ja - np. ThisIsMyEnumValue = 1 itd.) następnie możesz użyć bardzo prostego wyrażenia regularnego do wydrukowania przyjaznego formularza:

static string ToFriendlyCase(this string EnumString)
{
    return Regex.Replace(EnumString, "(?!^)([A-Z])", " $1");
}

Które można łatwo wywołać z dowolnego ciągu znaków:

Console.WriteLine("ConvertMyCrazyPascalCaseSentenceToFriendlyCase".ToFriendlyCase());

Wyjścia:

Convert My Crazy Pascal Case Sentence To Friendly Case

To oszczędza bieganie po domach tworzenie niestandardowych atrybutów i dołączanie ich do Twoich enum lub za pomocą tabel wyszukiwania, aby połączyć wartość enum z przyjaznym ciągiem, a najlepsze jest to samo zarządzanie i może być używane na każdym Pascalu Case string, który jest nieskończenie bardziej wielokrotnego użytku. Oczywiście nie pozwala to na posiadanie innej przyjaznej nazwy niż Twoje enum, które zapewnia Twoje rozwiązanie.

I do like your oryginalne rozwiązanie dla bardziej złożonych scenariuszy. Możesz wziąć swoje rozwiązanie o krok dalej i uczynić GetStringValue metodą rozszerzenia swojego enum, a następnie nie musisz odwoływać się do niego jak StringEnum.GetStringValue...

public static string GetStringValue(this AuthenticationMethod value)
{
  string output = null;
  Type type = value.GetType();
  FieldInfo fi = type.GetField(value.ToString());
  StringValue[] attrs = fi.GetCustomAttributes(typeof(StringValue), false) as StringValue[];
  if (attrs.Length > 0)
    output = attrs[0].Value;
  return output;
}

Możesz wtedy łatwo uzyskać do niego dostęp bezpośrednio z instancji enum:

Console.WriteLine(AuthenticationMethod.SSO.GetStringValue());
 74
Author: BenAlabaster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-12 13:03:08

Niestety refleksja nad uzyskaniem atrybutów na enumach jest dość powolna:

Zobacz to pytanie: ktoś zna szybki sposób, aby dostać się do niestandardowych atrybutów na wartości enum?

.ToString() jest również dość powolny na enumach.

Możesz jednak napisać metody rozszerzeń dla enum:

public static string GetName( this MyEnum input ) {
    switch ( input ) {
        case MyEnum.WINDOWSAUTHENTICATION:
            return "Windows";
        //and so on
    }
}

To nie jest świetne, ale będzie szybkie i nie będzie wymagało odbicia dla atrybutów lub nazwy pola.


C # 6 Update

Jeśli możesz używać C # 6 to nowy nameof operator działa dla enum, więc nameof(MyEnum.WINDOWSAUTHENTICATION) zostanie przekonwertowany na "WINDOWSAUTHENTICATION" w czasie kompilacji, co czyni go najszybszym sposobem uzyskania nazw enum.

Zauważ, że spowoduje to konwersję jawnego enum na stałą inlined, więc nie działa dla enum, które masz w zmiennej. Więc:

nameof(AuthenticationMethod.FORMS) == "FORMS"
Ale...
var myMethod = AuthenticationMethod.FORMS;
nameof(myMethod) == "myMethod"
 64
Author: Keith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:02

Używam metody rozszerzenia:

public static class AttributesHelperExtension
    {
        public static string ToDescription(this Enum value)
        {
            var da = (DescriptionAttribute[])(value.GetType().GetField(value.ToString())).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return da.Length > 0 ? da[0].Description : value.ToString();
        }
}

Teraz udekoruj enum z:

public enum AuthenticationMethod
{
    [Description("FORMS")]
    FORMS = 1,
    [Description("WINDOWSAUTHENTICATION")]
    WINDOWSAUTHENTICATION = 2,
    [Description("SINGLESIGNON ")]
    SINGLESIGNON = 3
}

Kiedy zadzwonisz

AuthenticationMethod.FORMS.ToDescription() dostaniesz "FORMS".

 53
Author: Mangesh Pimpalkar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-05 15:08:01

Po prostu użyj metody ToString()

public enum any{Tomato=0,Melon,Watermelon}

Aby odwołać się do ciągu Tomato, wystarczy użyć

any.Tomato.ToString();
 38
Author: chepe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-24 17:33:54

Używam atrybutu Description z systemu.Przestrzeń nazw ComponentModel. Po prostu udekoruj enum, a następnie użyj tego kodu, aby go odzyskać:

public static string GetDescription<T>(this object enumerationValue)
            where T : struct
        {
            Type type = enumerationValue.GetType();
            if (!type.IsEnum)
            {
                throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
            }

            //Tries to find a DescriptionAttribute for a potential friendly name
            //for the enum
            MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
            if (memberInfo != null && memberInfo.Length > 0)
            {
                object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

                if (attrs != null && attrs.Length > 0)
                {
                    //Pull out the description value
                    return ((DescriptionAttribute)attrs[0]).Description;
                }
            }
            //If we have no description attribute, just return the ToString of the enum
            return enumerationValue.ToString();

        }

Jako przykład:

public enum Cycle : int
{        
   [Description("Daily Cycle")]
   Daily = 1,
   Weekly,
   Monthly
}

Ten kod dobrze odpowiada enumom, w których nie potrzebujesz "przyjaznej nazwy" i zwrócisz tylko .ToString () z enum.

 26
Author: ,
Warning: date() expects parameter 2 to be long, string given in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54