Question

Mon énumération comprend les valeurs suivantes:

private enum PublishStatusses{
    NotCompleted,
    Completed,
    Error
};

Je souhaite cependant pouvoir afficher ces valeurs de manière conviviale.
Je n'ai pas besoin de pouvoir passer de chaîne en valeur à nouveau.

Était-ce utile?

La solution

J'utilise l'attribut Description de l'espace de noms System.ComponentModel. Décorez simplement l'énum:

private enum PublishStatusValue
{
    [Description("Not Completed")]
    NotCompleted,
    Completed,
    Error
};

Utilisez ensuite ce code pour le récupérer:

public static string GetDescription<T>(this T 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();
}

Autres conseils

Je le fais avec les méthodes d'extension:

public enum ErrorLevel
{
  None,
  Low,
  High,
  SoylentGreen
}

public static class ErrorLevelExtensions
{
  public static string ToFriendlyString(this ErrorLevel me)
  {
    switch(me)
    {
      case ErrorLevel.None:
        return "Everything is OK";
      case ErrorLevel.Low:
        return "SNAFU, if you know what I mean.";
      case ErrorLevel.High:
        return "Reaching TARFU levels";
      case ErrorLevel.SoylentGreen:
        return "ITS PEOPLE!!!!";
      default:
        return "Get your damn dirty hands off me you FILTHY APE!";
    }
  }
}

Peut-être qu'il me manque quelque chose, mais qu'est-ce qui ne va pas avec Enum.GetName?

public string GetName(PublishStatusses value)
{
    return Enum.GetName(typeof(PublishStatusses), value)
}

edit: pour les chaînes conviviales, vous devez passer par un .resource pour obtenir l’internationalisation / localisation, et il serait sans doute préférable d’utiliser une clé fixe basée sur la clé enum plutôt qu’un attribut décorateur sur la même chose.

J'ai créé une méthode d'extension inverse pour reconvertir la description en une valeur enum:

public static T ToEnumValue<T>(this string enumerationDescription) where T : struct
{
    var type = typeof(T);

    if (!type.IsEnum)
        throw new ArgumentException("ToEnumValue<T>(): Must be of enum type", "T");

    foreach (object val in System.Enum.GetValues(type))
        if (val.GetDescription<T>() == enumerationDescription)
            return (T)val;

    throw new ArgumentException("ToEnumValue<T>(): Invalid description for enum " + type.Name, "enumerationDescription");
}

La solution la plus simple consiste à utiliser une méthode d'extension personnalisée (au moins dans .NET 3.5 - vous pouvez simplement la convertir en méthode d'assistance statique pour les versions précédentes de l'infrastructure).

public static string ToCustomString(this PublishStatusses value)
{
    switch(value)
    {
        // Return string depending on value.
    }
    return null;
}

Je suppose ici que vous souhaitez renvoyer autre chose que le nom réel de la valeur enum (que vous pouvez obtenir simplement en appelant ToString).

Cet autre article est Java. Vous ne pouvez pas mettre de méthodes dans Enums en C #.

faites quelque chose comme ça:

PublishStatusses status = ...
String s = status.ToString();

Si vous souhaitez utiliser différentes valeurs d'affichage pour vos valeurs enum, vous pouvez utiliser les attributs et la réflexion.

La méthode la plus simple consiste simplement à inclure cette classe d'extension dans votre projet. Elle fonctionnera avec toutes les énumérations du projet:

public static class EnumExtensions
{
    public static string ToFriendlyString(this Enum code)
    {
        return Enum.GetName(code.GetType(), code);
    }
}

Utilisation:

enum ExampleEnum
{
    Demo = 0,
    Test = 1, 
    Live = 2
}

...

ExampleEnum ee = ExampleEnum.Live;
Console.WriteLine(ee.ToFriendlyString());

Quelques autres options plus primitives qui évitent les classes / types de référence:

  • Méthode Array
  • Méthode de structure imbriquée

Méthode Array

private struct PublishStatusses
{
    public static string[] Desc = {
        "Not Completed",
        "Completed",
        "Error"
    };

    public enum Id
    {
        NotCompleted = 0,
        Completed,
        Error
    };
}

Utilisation

string desc = PublishStatusses.Desc[(int)PublishStatusses.Id.Completed];

Méthode de structure imbriquée

private struct PublishStatusses
{
    public struct NotCompleted
    {
        public const int Id = 0;
        public const string Desc = "Not Completed";
    }

    public struct Completed
    {
        public const int Id = 1;
        public const string Desc = "Completed";
    }

    public struct Error
    {
        public const int Id = 2;
        public const string Desc = "Error";
    }            
}

Utilisation

int id = PublishStatusses.NotCompleted.Id;
string desc = PublishStatusses.NotCompleted.Desc;

Mise à jour (03/09/2018)

Un hybride de méthodes d'extension et de la première technique ci-dessus.

Je préfère que les énums soient définis là où ils & «appartiennent» à & «; (le plus proche de leur source d'origine et non dans un espace de nom global commun).

namespace ViewModels
{
    public class RecordVM
    {
        //public enum Enum { Minutes, Hours }
        public struct Enum
        {
            public enum Id { Minutes, Hours }
            public static string[] Name = { "Minute(s)", "Hour(s)" };
        }
    }
}

La méthode d'extension semble adaptée à un espace commun, et la & "localisée &"; la définition de l’énum rend maintenant la méthode d’extension plus détaillée.

namespace Common
{
    public static class EnumExtensions
    {
        public static string Name(this RecordVM.Enum.Id id)
        {
            return RecordVM.Enum.Name[(int)id];
        }
    }   
}

Un exemple d'utilisation de l'énum et de sa méthode d'extension.

namespace Views
{
    public class RecordView 
    {
        private RecordDataFieldList<string, string> _fieldUnit;

        public RecordView()
        {
            _fieldUnit.List = new IdValueList<string, string>
            {            
                new ListItem<string>((int)RecordVM.Enum.Id.Minutes, RecordVM.Enum.Id.Minutes.Name()),
                new ListItem<string>((int)RecordVM.Enum.Id.Hours, RecordVM.Enum.Id.Hours.Name())
            };
        }

        private void Update()
        {    
            RecordVM.Enum.Id eId = DetermineUnit();

            _fieldUnit.Input.Text = _fieldUnit.List.SetSelected((int)eId).Value;
        }
    }
}

Remarque: j'ai en fait décidé d'éliminer le Enum wrapper (et le Name tableau), car il est préférable que les chaînes de noms proviennent d'une ressource (fichier de configuration ou base de données) au lieu de être codé en dur et parce que j'ai fini par mettre la méthode d'extension dans le ViewModels espace de noms (juste dans un fichier différent, & "; CommonVM.cs &";). De plus, le tout .Id devient distrayant et encombrant.

namespace ViewModels
{
    public class RecordVM
    {
        public enum Enum { Minutes, Hours }
        //public struct Enum
        //{
        //    public enum Id { Minutes, Hours }
        //    public static string[] Name = { "Minute(s)", "Hour(s)" };
        //}
    }
}

CommonVM.cs

//namespace Common
namespace ViewModels
{
    public static class EnumExtensions
    {
        public static string Name(this RecordVM.Enum id)
        {
            //return RecordVM.Enum.Name[(int)id];
            switch (id)
            {
                case RecordVM.Enum.Minutes: return "Minute(s)";                    
                case RecordVM.Enum.Hours: return "Hour(s)";
                default: return null;
            }
        }
    }   
}

Un exemple d'utilisation de l'énum et de sa méthode d'extension.

namespace Views
{
    public class RecordView 
    {
        private RecordDataFieldList<string, string> _fieldUnit

        public RecordView()
        {
            _fieldUnit.List = new IdValueList<string, string>
            {            
                new ListItem<string>((int)RecordVM.Enum.Id.Minutes, RecordVM.Enum.Id.Minutes.Name()),
                new ListItem<string>((int)RecordVM.Enum.Id.Hours, RecordVM.Enum.Id.Hours.Name())
            };
        }

        private void Update()
        {    
            RecordVM.Enum eId = DetermineUnit();

            _fieldUnit.Input.Text = _fieldUnit.List.SetSelected((int)eId).Value;
        }
    }
}

Vous pouvez utiliser le package Humanizer avec Humanize Enums . Un exemple:

enum PublishStatusses
{
    [Description("Custom description")]
    NotCompleted,
    AlmostCompleted,
    Error
};

alors vous pouvez utiliser Humanize la méthode d'extension sur enum directement:

var st1 = PublishStatusses.NotCompleted;
var str1 = st1.Humanize(); // will result in Custom description

var st2 = PublishStatusses.AlmostCompleted;
var str2 = st2.Humanize(); // will result in Almost completed (calculated automaticaly)

En ce qui concerne Ray Booysen, le code contient un bogue: Enum ToString avec des chaînes conviviales

Vous devez prendre en compte plusieurs attributs dans les valeurs enum.

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 && attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault() != null)
            {
                //Pull out the description value
                return ((DescriptionAttribute)attrs.Where(t=>t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault()).Description;
            }
        }
        //If we have no description attribute, just return the ToString of the enum
        return enumerationValue.ToString();
public enum MyEnum
{
    [Description("Option One")]
    Option_One
}

public static string ToDescriptionString(this Enum This)
{
    Type type = This.GetType();

    string name = Enum.GetName(type, This);

    MemberInfo member = type.GetMembers()
        .Where(w => w.Name == name)
        .FirstOrDefault();

    DescriptionAttribute attribute = member != null
        ? member.GetCustomAttributes(true)
            .Where(w => w.GetType() == typeof(DescriptionAttribute))
            .FirstOrDefault() as DescriptionAttribute
        : null;

    return attribute != null ? attribute.Description : name;
}

Au lieu d'utiliser une énumération, utilisez une classe statique.

remplacer

private enum PublishStatuses{
    NotCompleted,
    Completed,
    Error
};

avec

private static class PublishStatuses{
    public static readonly string NotCompleted = "Not Completed";
    public static readonly string Completed = "Completed";
    public static readonly string Error = "Error";
};

il sera utilisé comme ceci

PublishStatuses.NotCompleted; // "Not Completed"

Problème lors de l'utilisation de la méthode d'extension & supérieure; " solutions:

Un enum privé est souvent utilisé dans une autre classe. La solution de la méthode d'extension n'est pas valide ici car elle doit être dans sa propre classe. Cette solution peut être privée et intégrée à une autre classe.

Je suis un fan de VB.NET, voici donc ma version, qui associe la méthode DescriptionAttribute à une méthode d'extension. Premièrement, les résultats:

Imports System.ComponentModel ' For <Description>

Module Module1
  ''' <summary>
  ''' An Enum type with three values and descriptions
  ''' </summary>
  Public Enum EnumType
    <Description("One")>
    V1 = 1

    ' This one has no description
    V2 = 2

    <Description("Three")>
    V3 = 3
  End Enum

  Sub Main()
    ' Description method is an extension in EnumExtensions
    For Each v As EnumType In [Enum].GetValues(GetType(EnumType))
      Console.WriteLine("Enum {0} has value {1} and description {2}",
        v,
        CInt(v),
        v.Description
      )
    Next
    ' Output:
    ' Enum V1 has value 1 and description One
    ' Enum V2 has value 2 and description V2
    ' Enum V3 has value 3 and description Three
  End Sub
End Module

Élément de base: une énumération appelée EnumType avec trois valeurs V1, V2 et V3. La & "Magie &"; se passe dans l'appel Console.WriteLine dans Sub Main (), où le dernier argument est simplement v.Description. Ceci retourne & Quot; Un & Quot; pour V1, " V2 " pour V2 et & "Trois &"; pour V3. Cette méthode Description est en fait une méthode d'extension, définie dans un autre module appelé EnumExtensions:

Option Strict On
Option Explicit On
Option Infer Off

Imports System.Runtime.CompilerServices
Imports System.Reflection
Imports System.ComponentModel

Module EnumExtensions
  Private _Descriptions As New Dictionary(Of String, String)

  ''' <summary>
  ''' This extension method adds a Description method
  ''' to all enum members. The result of the method is the
  ''' value of the Description attribute if present, else
  ''' the normal ToString() representation of the enum value.
  ''' </summary>
  <Extension>
  Public Function Description(e As [Enum]) As String
    ' Get the type of the enum
    Dim enumType As Type = e.GetType()
    ' Get the name of the enum value
    Dim name As String = e.ToString()

    ' Construct a full name for this enum value
    Dim fullName As String = enumType.FullName + "." + name

    ' See if we have looked it up earlier
    Dim enumDescription As String = Nothing
    If _Descriptions.TryGetValue(fullName, enumDescription) Then
      ' Yes we have - return previous value
      Return enumDescription
    End If

    ' Find the value of the Description attribute on this enum value
    Dim members As MemberInfo() = enumType.GetMember(name)
    If members IsNot Nothing AndAlso members.Length > 0 Then
      Dim descriptions() As Object = members(0).GetCustomAttributes(GetType(DescriptionAttribute), False)
      If descriptions IsNot Nothing AndAlso descriptions.Length > 0 Then
        ' Set name to description found
        name = DirectCast(descriptions(0), DescriptionAttribute).Description
      End If
    End If

    ' Save the name in the dictionary:
    _Descriptions.Add(fullName, name)

    ' Return the name
    Return name
  End Function
End Module

La recherche d'attributs de description à l'aide de Reflection étant lente, les recherches sont également mises en cache dans un fichier privé Dictionary, renseigné à la demande.

(Désolé pour la solution VB.NET - il devrait être relativement simple de la traduire en C #, et mon C # est rouillé sur de nouveaux sujets tels que les extensions)

Nettoyez le résumé des suggestions ci-dessus avec l'exemple:

namespace EnumExtensions {

using System;
using System.Reflection;

public class TextAttribute : Attribute {
   public string Text;
   public TextAttribute( string text ) {
      Text = text;
   }//ctor
}// class TextAttribute

public static class EnumExtender {

public static string ToText( this Enum enumeration ) {

   MemberInfo[] memberInfo = enumeration.GetType().GetMember( enumeration.ToString() );

   if ( memberInfo != null && memberInfo.Length > 0 ) {

      object[] attributes = memberInfo[ 0 ].GetCustomAttributes( typeof(TextAttribute),  false );

      if ( attributes != null && attributes.Length > 0 ) {
         return ( (TextAttribute)attributes[ 0 ] ).Text;
      }

   }//if

   return enumeration.ToString();

}//ToText

}//class EnumExtender

}//namespace

UTILISATION:

using System;
using EnumExtensions;

class Program {

public enum Appearance {

  [Text( "left-handed" ) ]
  Left,

  [Text( "right-handed" ) ]
  Right,

}//enum

static void Main( string[] args ) {

   var appearance = Appearance.Left;
   Console.WriteLine( appearance.ToText() );

}//Main

}//class

Il s'agit d'une mise à jour du code de Ray Booysen qui utilise la méthode générique GetCustomAttributes et LINQ pour rendre les choses un peu plus ordonnées.

    /// <summary>
    /// Gets the value of the <see cref="T:System.ComponentModel.DescriptionAttribute"/> on an struct, including enums.  
    /// </summary>
    /// <typeparam name="T">The type of the struct.</typeparam>
    /// <param name="enumerationValue">A value of type <see cref="T:System.Enum"/></param>
    /// <returns>If the struct has a Description attribute, this method returns the description.  Otherwise it just calls ToString() on the struct.</returns>
    /// <remarks>Based on http://stackoverflow.com/questions/479410/enum-tostring/479417#479417, but useful for any struct.</remarks>
    public static string GetDescription<T>(this T enumerationValue) where T : struct
    {
        return enumerationValue.GetType().GetMember(enumerationValue.ToString())
                .SelectMany(mi => mi.GetCustomAttributes<DescriptionAttribute>(false),
                    (mi, ca) => ca.Description)
                .FirstOrDefault() ?? enumerationValue.ToString();
    }   

Résumé encore plus net:

using System;
using System.Reflection;

public class TextAttribute : Attribute
{
    public string Text;
    public TextAttribute(string text)
    {
        Text = text;
    }
}  

public static class EnumExtender
{
    public static string ToText(this Enum enumeration)
    {
        var memberInfo = enumeration.GetType().GetMember(enumeration.ToString());
        if (memberInfo.Length <= 0) return enumeration.ToString();

        var attributes = memberInfo[0].GetCustomAttributes(typeof(TextAttribute), false);
        return attributes.Length > 0 ? ((TextAttribute)attributes[0]).Text : enumeration.ToString();
    }
}

Même utilisation que décrit par le trait de soulignement.

Utilisez Enum.GetName

À partir du lien ci-dessus ...

using System;

public class GetNameTest {
    enum Colors { Red, Green, Blue, Yellow };
    enum Styles { Plaid, Striped, Tartan, Corduroy };

    public static void Main() {

        Console.WriteLine("The 4th value of the Colors Enum is {0}", Enum.GetName(typeof(Colors), 3));
        Console.WriteLine("The 4th value of the Styles Enum is {0}", Enum.GetName(typeof(Styles), 3));
    }
}
// The example displays the following output:
//       The 4th value of the Colors Enum is Yellow
//       The 4th value of the Styles Enum is Corduroy

Pour les drapeaux énumérés, y compris.

    public static string Description(this Enum value)
    {
        Type type = value.GetType();

        List<string> res = new List<string>();
        var arrValue = value.ToString().Split(',').Select(v=>v.Trim());
        foreach (string strValue in arrValue)
        {
            MemberInfo[] memberInfo = type.GetMember(strValue);
            if (memberInfo != null && memberInfo.Length > 0)
            {
                object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

                if (attrs != null && attrs.Length > 0 && attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault() != null)
                {
                    res.Add(((DescriptionAttribute)attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault()).Description);
                }
                else
                    res.Add(strValue);
            }
            else
                res.Add(strValue);
        }

        return res.Aggregate((s,v)=>s+", "+v);
    }

Je pense que le meilleur (et le plus simple) moyen de résoudre votre problème consiste à écrire une méthode d'extension pour votre enum:

public static string GetUserFriendlyString(this PublishStatusses status)
    {

    }

Si vous voulez quelque chose de complètement personnalisable, essayez ma solution ici:

http : //www.kevinwilliampang.com/post/Mapping-Enums-To-Strings-and-Strings-to-Enums-in-NET.aspx

En gros, l'article explique comment associer des attributs de description à chacune de vos énumérations et fournit un moyen générique de mapper d'énum en description.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top