So fügen Sie Enums Erweiterungsmethoden hinzu


122

Ich habe diesen Enum-Code:

enum Duration { Day, Week, Month };

Kann ich eine Erweiterungsmethode für diese Aufzählung hinzufügen?




kurze Antwort, ja. In diesem speziellen Fall möchten Sie vielleicht die Verwendung vonTimeSpan
Jodrell

1
Die Verwendung von Erweiterungsmethoden für eine Aufzählung würde mich schmutzig machen. Erstellen Sie eine Klasse, um zu kapseln, was benötigt wird. Halten Sie eine Aufzählung so einfach wie möglich. Wenn Sie mehr Logik benötigen, erstellen Sie eine Duration-Klasse, die Tag, Woche, Monat plus verfügbar macht und jede andere Logik enthält, die in der Erweiterungsmethode enthalten gewesen wäre.
Jason Evans

2
Ich mag Enum-Erweiterungsmethoden für Flag-Gruppen. Ich ziehe es in , wenn Klauseln zum Beispiel Day.IsWorkday()über (Day & Days.Workday) > 0mit Days.Workdaydefiniert Monday | Tuesday ... | Friday. Ersteres ist meiner Meinung nach klarer und hat genau Letzteres umgesetzt.
Sebastian Werk

Antworten:


114

Laut dieser Seite :

Erweiterungsmethoden bieten eine Möglichkeit, Methoden für vorhandene Klassen so zu schreiben, wie andere Personen in Ihrem Team sie möglicherweise tatsächlich entdecken und verwenden. Angesichts der Tatsache, dass Aufzählungen Klassen wie jede andere sind, sollte es nicht allzu überraschend sein, dass Sie sie erweitern können, wie zum Beispiel:

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

Ich denke, Aufzählungen sind im Allgemeinen nicht die beste Wahl, aber zumindest können Sie so einen Teil des Schalters / der Handhabung zentralisieren und ein wenig abstrahieren, bis Sie etwas Besseres tun können. Denken Sie daran, zu überprüfen, ob die Werte ebenfalls im Bereich liegen.

Weitere Informationen finden Sie hier bei Microsft MSDN.


Ich glaube, der Kommentar "Aufzählungen sind böse" ist fehl am Platz, hat aber eine Grundlage in der Realität. Ich finde, dass Aufzählungen ein Problem sein können, das überbeansprucht wird, da sie Sie irgendwie an bestimmte Kontexte und Verhaltensweisen binden.
Ed Schwehm

1
Aufzählungen in C # saugen irgendwie, weil dies kompiliert und ausgeführt wird:Duration d = 0;
Graham

16
Given that enums are classesNein, sie sind keine Klassen.
Flügelspieler Sendon

1
Ich verwende diese Art der Erweiterung nur, wenn es direkt um die Aufzählung geht, wie Wochentage und Erweiterungsmethoden IsWeekday (), IsWeekendday (). Klassen sollen jedoch Verhaltensweisen kapseln. Wenn also viele oder komplizierte Verhaltensweisen gekapselt werden müssen, ist eine Klasse wahrscheinlich besser. Wenn es begrenzt und einfach ist, finde ich persönlich Erweiterungen für Aufzählungen in Ordnung. Wie bei den meisten Entwurfsentscheidungen gibt es unscharfe Grenzen zwischen Auswahlmöglichkeiten (IMO). Es ist erwähnenswert, dass Erweiterungen nur für statische Klassen der obersten Ebene und nicht für verschachtelte Klassen durchgeführt werden können. Wenn Ihre Aufzählung Teil einer Klasse ist, müssen Sie eine Klasse erstellen.
FreeText

51

Sie können dem Aufzählungstyp auch eine Erweiterungsmethode anstelle einer Instanz der Aufzählung hinzufügen:

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

Sie können die oben beschriebene Erweiterungsmethode aufrufen, indem Sie Folgendes tun:

var result = Enum<Duration>.Count;

Es ist keine echte Erweiterungsmethode. Dies funktioniert nur, weil Enum <> ein anderer Typ als System.Enum ist.


Kann die Klasse staticsicherstellen, dass sich alle Methoden wie Erweiterungen verhalten?
Jatin Sanghvi

15
Für zukünftige Leser: Die Namensmehrdeutigkeit von Enum<T>ist etwas verwirrend. Die Klasse könnte auch aufgerufen werden EnumUtils<T>und der Methodenaufruf würde in aufgelöst EnumUtils<Duration>.Count.
Namoshek

46

Natürlich können Sie zum Beispiel das DescriptionAttribuefür Ihre enumWerte verwenden:

using System.ComponentModel.DataAnnotations;

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

    [Description("Five days")]
    Week,

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

Jetzt möchten Sie in der Lage sein, etwas zu tun wie:

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

Ihre Erweiterungsmethode GetDescription()kann wie folgt geschrieben werden:

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

Ich wollte eine Erweiterung für fast genau das erstellen, was Sie als Beispiel getan haben, mit Ausnahme meiner Verwendung von DisplayAttribute Localized GetDescription. Prost
George

Dies ist eine schöne Alternative, obwohl ich denke, dass der Namespace nur System.ComponentModel ist?
TomDestry

Schöne Perspektive und danke, dass Sie die Implementierung sowie den Erweiterungscode gezeigt haben. Zum Anhäufen: Mit Ihrer Implementierung können Sie es auch folgendermaßen aufrufen: var description = Duration.Week.GetDescription ();
Spencer Sullivan

30

Alle Antworten sind großartig, aber es geht darum, einer bestimmten Art von Aufzählung eine Erweiterungsmethode hinzuzufügen.

Was ist, wenn Sie allen Aufzählungen eine Methode hinzufügen möchten, z. B. die Rückgabe eines int mit dem aktuellen Wert anstelle einer expliziten Umwandlung?

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

Der Trick dahinter IConvertibleist die Vererbungshierarchie, siehe MDSN

Vielen Dank an ShawnFeatherly für seine Antwort


1
die beste Antwort!
Marco Alves

Das Gleiche gilt. Es funktioniert, wenn ich die Nebenstelle direkt MyExtention.DoThing(myvalue)myvalue.DoThing()
anrufe


7

Sie können auch für alles eine Erweiterung erstellen object(obwohl dies nicht als Best Practice angesehen wird ). Verstehen Sie eine Erweiterungsmethode nur als public staticMethode. Sie können für Methoden einen beliebigen Parametertyp verwenden.

public static class DurationExtensions
{
  public static int CalculateDistanceBetween(this Duration first, Duration last)
  {
    //Do something here
  }
}

5

Siehe MSDN .

public static class Extensions
{
  public static string SomeMethod(this Duration enumValue)
  {
    //Do something here
    return enumValue.ToString("D"); 
  }
}

7
Ein voidRückgabewert für eine Aufzählung ist irgendwie komisch. Ich würde über eine realistischere Stichprobe nachdenken.
Psubsee2003

3
@ psubsee2003 hat das OP sicherlich genug Wissen, um dies an seine Bedürfnisse anzupassen? Warum ist das Beispiel wichtig? Es reicht aus, um die erste Frage zu beantworten.
LukeHennerley

3
Bin ich der einzige, der die Codebeispiele auf MSDN komisch findet? Meistens müssen Sie sich wirklich anstrengen, um zu verstehen, was sie versuchen!
Gestapelt

0

Wir haben gerade eine Enum-Erweiterung für c # https://github.com/simonmau/enum_ext erstellt

Es ist nur eine Implementierung für das Typensafeenum, aber es funktioniert großartig, also haben wir ein Paket zum Teilen erstellt - viel Spaß damit

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

Ich weiß, dass das Beispiel irgendwie nutzlos ist, aber Sie bekommen die Idee;)


0

Eine einfache Problemumgehung.

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

        return ( int ) ( IConvertible ) payLoad;

    }
}

int num = YourEnum.AItem.ToInt();
Console.WriteLine("num : ", num);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.