Comment ajouter des méthodes d'extension aux Enums

122

J'ai ce code Enum:

enum Duration { Day, Week, Month };

Puis-je ajouter une méthode d'extension pour cette énumération?

user2110292
la source
1
Avez-vous vu cette? stackoverflow.com/questions/2422113/…
badpanda
1
Aussi, ceci. stackoverflow.com/questions/276585/…
badpanda
réponse courte, oui. Dans ce cas précis, vous voudrez peut-être envisager l'utilisation deTimeSpan
Jodrell
1
Utiliser des méthodes d'extension sur une énumération me ferait me sentir sale. Créez une classe pour encapsuler ce qui est nécessaire. Gardez une énumération aussi simple que possible. Si vous avez besoin de plus de logique associée, créez une classe Duration qui expose jour, semaine, mois plus contient toute autre logique qui aurait été dans la méthode d'extension.
Jason Evans
2
J'aime avoir des méthodes d'extension enum pour les groupes d'indicateurs. Je préfère si des clauses par exemple Day.IsWorkday()sur (Day & Days.Workday) > 0des Days.Workdaydéfinis comme Monday | Tuesday ... | Friday. Le premier est plus clair à mon avis et a exactement le second mis en œuvre.
Sebastian Werk

Réponses:

114

Selon ce site :

Les méthodes d'extension fournissent un moyen d'écrire des méthodes pour des classes existantes d'une manière que d'autres personnes de votre équipe pourraient réellement découvrir et utiliser. Étant donné que les énumérations sont des classes comme les autres, il ne devrait pas être trop surprenant que vous puissiez les étendre, comme:

enum Duration { Day, Week, Month };

static class DurationExtensions 
{
  public static DateTime From(this Duration duration, DateTime dateTime) 
  {
    switch (duration) 
    {
      case Day:   return dateTime.AddDays(1);
      case Week:  return dateTime.AddDays(7);
      case Month: return dateTime.AddMonths(1);
      default:    throw new ArgumentOutOfRangeException("duration");
    }
  }
}

Je pense que les énumérations ne sont pas le meilleur choix en général, mais au moins cela vous permet de centraliser une partie de la gestion des commutateurs / if et de les abstraire un peu jusqu'à ce que vous puissiez faire quelque chose de mieux. N'oubliez pas de vérifier que les valeurs sont également comprises.

Vous pouvez en savoir plus ici sur Microsft MSDN.

Équipage d'un homme
la source
Je crois que le commentaire "enums are evil" est déplacé mais a un fondement dans la réalité. Je trouve que les énumérations peuvent être un problème surutilisées, car elles vous enferment en quelque sorte dans certains contextes et comportements.
Ed Schwehm
1
Les énumérations en C # sont nulles parce que cela compile et s'exécute:Duration d = 0;
Graham
16
Given that enums are classesnon ce ne sont pas des cours.
Ailier Sendon
1
J'utilise ce type d'extension uniquement s'il s'agit directement de l'énumération, comme les jours de la semaine et les méthodes d'extension IsWeekday (), IsWeekendday (). Mais les classes sont destinées à encapsuler des comportements, donc s'il y a beaucoup de comportements compliqués à encapsuler, une classe est probablement meilleure. Si c'est limité et basique, je trouve personnellement que les extensions sur les énumérations sont correctes. Comme pour la plupart des décisions de conception, il existe des frontières floues entre les choix (IMO). Il convient de noter que les extensions ne peuvent être effectuées que sur des classes statiques de niveau supérieur, pas sur des classes imbriquées. Si votre énumération fait partie d'une classe, vous devrez créer une classe.
FreeText
51

Vous pouvez également ajouter une méthode d'extension au type Enum plutôt qu'une instance de Enum:

/// <summary> Enum Extension Methods </summary>
/// <typeparam name="T"> type of Enum </typeparam>
public class Enum<T> where T : struct, IConvertible
{
    public static int Count
    {
        get
        {
            if (!typeof(T).IsEnum)
                throw new ArgumentException("T must be an enumerated type");

            return Enum.GetNames(typeof(T)).Length;
        }
    }
}

Vous pouvez appeler la méthode d'extension ci-dessus en faisant:

var result = Enum<Duration>.Count;

Ce n'est pas une véritable méthode d'extension. Cela fonctionne uniquement car Enum <> est d'un type différent de System.Enum.

ShawnFeatherly
la source
La classe peut-elle statics'assurer que toutes ses méthodes se comportent comme des extensions?
Jatin Sanghvi
15
Pour les futurs lecteurs: l'ambiguïté du nom de Enum<T>est un peu déroutante. La classe pourrait également être appelée EnumUtils<T>et l'appel de méthode se résoudrait en EnumUtils<Duration>.Count.
Namoshek
46

Bien sûr, vous pouvez, par exemple, utiliser le DescriptionAttribuesur vos enumvaleurs:

using System.ComponentModel.DataAnnotations;

public enum Duration 
{ 
    [Description("Eight hours")]
    Day,

    [Description("Five days")]
    Week,

    [Description("Twenty-one days")] 
    Month 
}

Vous voulez maintenant pouvoir faire quelque chose comme:

Duration duration = Duration.Week;
var description = duration.GetDescription(); // will return "Five days"

Votre méthode d'extension GetDescription()peut être écrite comme suit:

using System.ComponentModel;
using System.Reflection;

public static string GetDescription(this Enum value)
{
    FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
    if (fieldInfo == null) return null;
    var attribute = (DescriptionAttribute)fieldInfo.GetCustomAttribute(typeof(DescriptionAttribute));
    return attribute.Description;
}
Empilé
la source
Je cherchais à créer une extension pour presque exactement ce que vous avez fait, sauf mon utilisation de DisplayAttribute Localized GetDescription. cheers
George
C'est une bonne alternative, même si je pense que l'espace de noms est juste System.ComponentModel?
TomDestry
Belle perspective et merci d'avoir montré l'implémentation ainsi que le code d'extension. Pour empiler: avec votre implémentation, vous pouvez également l'appeler comme ceci: var description = Duration.Week.GetDescription ();
Spencer Sullivan
31

Toutes les réponses sont excellentes, mais elles parlent d'ajouter une méthode d'extension à un type spécifique d'énumération.

Que faire si vous souhaitez ajouter une méthode à toutes les énumérations, comme renvoyer un int de la valeur actuelle au lieu d'un cast explicite?

public static class EnumExtensions
{
    public static int ToInt<T>(this T soure) where T : IConvertible//enum
    {
        if (!typeof(T).IsEnum)
            throw new ArgumentException("T must be an enumerated type");

        return (int) (IConvertible) soure;
    }

    //ShawnFeatherly funtion (above answer) but as extention method
    public static int Count<T>(this T soure) where T : IConvertible//enum
    {
        if (!typeof(T).IsEnum)
            throw new ArgumentException("T must be an enumerated type");

        return Enum.GetNames(typeof(T)).Length;
    }
}

L'astuce derrière IConvertibleest sa hiérarchie d'héritage voir MDSN

Merci à ShawnFeatherly pour sa réponse

Basheer AL-MOMANI
la source
1
la meilleure réponse!
Marco Alves
Idem. Cela fonctionne si j'appelle l'extension directement (par exemple MyExtention.DoThing(myvalue)) mais ne m'attache pas réellement à l'énumération (par exemple myvalue.DoThing())
Sinaesthetic
1
FYI, C # 7.3 prend désormais en charge Enum en tant que contrainte de type générique
redtetrahedron
7

Vous pouvez créer une extension pour n'importe quoi, même object(bien que ce ne soit pas considéré comme une meilleure pratique ). Comprenez une méthode d'extension comme une public staticméthode. Vous pouvez utiliser le type de paramètre de votre choix sur les méthodes.

public static class DurationExtensions
{
  public static int CalculateDistanceBetween(this Duration first, Duration last)
  {
    //Do something here
  }
}
Tim Schmelter
la source
5

Voir MSDN .

public static class Extensions
{
  public static string SomeMethod(this Duration enumValue)
  {
    //Do something here
    return enumValue.ToString("D"); 
  }
}
LukeHennerley
la source
7
Une voidvaleur de retour sur une énumération est un peu bizarre. Je penserais à un échantillon plus réaliste.
psubsee2003
3
@ psubsee2003 l'OP a sûrement assez de connaissances pour changer cela en fonction de ses besoins? Pourquoi l'échantillon est-il important, il suffit de répondre à la question initiale.
LukeHennerley
3
Suis-je le seul à trouver bizarre les exemples de code sur MSDN? La plupart du temps, vous avez besoin d'un réel effort pour comprendre ce qu'ils essaient de faire!
Empilé le
0

nous venons de créer une extension enum pour c # https://github.com/simonmau/enum_ext

C'est juste une implémentation pour le typesafeenum, mais cela fonctionne très bien, nous avons donc créé un package à partager - amusez-vous avec

public sealed class Weekday : TypeSafeNameEnum<Weekday, int>
{
    public static readonly Weekday Monday = new Weekday(1, "--Monday--");
    public static readonly Weekday Tuesday = new Weekday(2, "--Tuesday--");
    public static readonly Weekday Wednesday = new Weekday(3, "--Wednesday--");
    ....

    private Weekday(int id, string name) : base(id, name)
    {
    }

    public string AppendName(string input)
    {
        return $"{Name} {input}";
    }
}

Je sais que l'exemple est un peu inutile, mais vous voyez l'idée;)

Simonmau
la source
0

Une solution de contournement simple.

public static class EnumExtensions
{
    public static int ToInt(this Enum payLoad) {

        return ( int ) ( IConvertible ) payLoad;

    }
}

int num = YourEnum.AItem.ToInt();
Console.WriteLine("num : ", num);
M. Hamza Rajput
la source