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?

user2110292
quelle
1
Hast du das gesehen? stackoverflow.com/questions/2422113/…
Badpanda
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.

Ein-Mann-Crew
quelle
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.

ShawnFeatherly
quelle
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;
}
Gestapelt
quelle
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

Basheer AL-MOMANI
quelle
1
die beste Antwort!
Marco Alves
Das Gleiche gilt. Es funktioniert, wenn ich die Nebenstelle direkt MyExtention.DoThing(myvalue)myvalue.DoThing()
anrufe
1
Zu
Ihrer Information
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
  }
}
Tim Schmelter
quelle
5

Siehe MSDN .

public static class Extensions
{
  public static string SomeMethod(this Duration enumValue)
  {
    //Do something here
    return enumValue.ToString("D"); 
  }
}
LukeHennerley
quelle
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;)

Simonmau
quelle
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);
M. Hamza Rajput
quelle