Mögliches Duplikat:
Kennt jemand eine gute Problemumgehung für das Fehlen einer allgemeinen Aufzählungsbeschränkung?
Was ist der Grund, warum C # keine Typbeschränkungen für Enum
zulässt? Ich bin mir sicher, dass hinter dem Wahnsinn eine Methode steckt, aber ich würde gerne verstehen, warum das nicht möglich ist.
Nachstehend ist aufgeführt, was ich (theoretisch) tun möchte.
public static T GetEnum<T>(this string description) where T : Enum
{
...
}
Dies ist eine gelegentlich angeforderte Funktion.
Wie ich gerne erwähne, werden ALLE Funktionen erst implementiert, wenn jemand die Funktion entwirft, spezifiziert, implementiert, testet, dokumentiert und ausliefert. Bisher hat das noch niemand gemacht. Es gibt keinen besonders ungewöhnlichen Grund, warum nicht; Wir haben viele andere Dinge zu tun, begrenzte Budgets, und dieses hat es nie über das "Wäre das nicht schön?" Diskussion im Sprachdesign-Team.
Die CLR unterstützt es nicht. Damit es funktioniert, müssen wir zusätzlich zur Spracharbeit auch noch Laufzeitarbeit leisten. (siehe Antwortkommentare)
Ich kann sehen, dass es ein paar anständige Anwendungsfälle gibt, aber keine davon ist so überzeugend, dass wir diese Arbeit eher als eine der Hunderten anderen Funktionen ausführen würden, die viel häufiger angefordert werden oder überzeugender und weiterreichender sind Anwendungsfälle. (Wenn wir mit diesem Code nicht weiterkommen wollen, würde ich die Delegate-Einschränkungen persönlich so priorisieren, dass sie weit über den Enum-Einschränkungen liegen.)
Eigentlich ist es mit einem hässlichen Trick möglich. Es kann jedoch nicht für Erweiterungsmethoden verwendet werden.
public abstract class Enums<Temp> where Temp : class {
public static TEnum Parse<TEnum>(string name) where TEnum : struct, Temp {
return (TEnum)Enum.Parse(typeof(TEnum), name);
}
}
public abstract class Enums : Enums<Enum> { }
Enums.Parse<DateTimeKind>("Local")
Wenn du willst, kannst du Enums<Temp>
ein privater Konstruktor und eine öffentlich verschachtelte abstrakte geerbte Klasse mit Temp
als Enum
, um geerbte Versionen für Nicht-Enums zu verhindern.
Beachten Sie, dass Sie diesen Trick nicht verwenden können, um Erweiterungsmethoden zu erstellen.
public static T GetEnum<T>(this string description) where T : struct
{
return (T)Enum.Parse(typeof(T), description);
}
Beantwortet es Ihre Frage?
IL Weben mit ExtraConstraints
public static T GetEnum<[EnumConstraint] T>(this string description)
{
...
}
public static T GetEnum<T>(this string description) where T : Enum
{
...
}
Hier ist eine VB.NET-Version von SLaks ausgezeichneter hässlicher Trick mit Imports
als "typedef":
'Base namespace "EnumConstraint"
Imports Enums = EnumConstraint.Enums(Of System.Enum)
Public NotInheritable Class Enums(Of Temp As Class)
Private Sub New()
End Sub
Public Shared Function Parse(Of TEnum As {Temp, Structure})(ByVal Name As String) As TEnum
Return DirectCast([Enum].Parse(GetType(TEnum), Name), TEnum)
End Function
Public Shared Function IsDefined(Of TEnum As {Temp, Structure})(ByVal Value As TEnum) As Boolean
Return [Enum].IsDefined(GetType(TEnum), Value)
End Function
Public Shared Function HasFlags(Of TEnum As {Temp, Structure})(ByVal Value As TEnum, ByVal Flags As TEnum) As Boolean
Dim flags64 As Long = Convert.ToInt64(Flags)
Return (Convert.ToInt64(Value) And flags64) = flags64
End Function
End Class
Module Module1
Sub Main()
Dim k = Enums.Parse(Of DateTimeKind)("Local")
Console.WriteLine("{0} = {1}", k, CInt(k))
Console.WriteLine("IsDefined({0}) = {1}", k, Enums.IsDefined(k))
k = DirectCast(k * 2, DateTimeKind)
Console.WriteLine("IsDefined({0}) = {1}", k, Enums.IsDefined(k))
Console.WriteLine(" {0} same as {1} Or {2}: {3} ", IO.FileAccess.ReadWrite, IO.FileAccess.Read, IO.FileAccess.Write, _
Enums.HasFlags(IO.FileAccess.ReadWrite, IO.FileAccess.Read Or IO.FileAccess.Write))
' These fail to compile as expected:
'Console.WriteLine(Enums.HasFlags(IO.FileAccess.ReadWrite, IO.FileOptions.RandomAccess))
'Console.WriteLine(Enums.HasFlags(Of IO.FileAccess)(IO.FileAccess.ReadWrite, IO.FileOptions.RandomAccess))
If Debugger.IsAttached Then _
Console.ReadLine()
End Sub
End Module
Ausgabe:
Local = 2
IsDefined(Local) = True
IsDefined(4) = False
ReadWrite same as Read Or Write: True
Eine eigentümliche Sache ist, dass es eine ganze Reihe von generischen Enum-Methoden gibt, die Sie schreiben möchten, deren Implementierung vom "Basistyp" der Enumeration abhängt.
Mit dem "Basis" -Typ einer Aufzählung, E
, meine ich den Typ im Namensraum System
, dessen Name mit dem Namen des Mitglieds der erhaltenen System.TypeCode
- Aufzählung identisch ist durch Aufrufen von System.Type.GetTypeCode(System.Type)
für den Typ E
. Wenn die Aufzählung in C # deklariert wurde, ist dies derselbe Typ, von dem deklariert wurde, dass er "erbt" (ich bin nicht sicher, wie dies in der Spezifikation offiziell heißt). Der Basistyp der folgenden Aufzählung Animal
ist beispielsweise System.Byte
:
public enum Animal : byte
{
Moose,
Squirrel
}
Es ist möglich, solche Methoden mit switch-Anweisungen zu schreiben, aber es ist sicher hässlich, dass Sie keine stark typisierten Parameter oder Rückgabetypen erhalten können, deren Typ der Basistyp der Aufzählung ist, und dass Sie entweder die Metadatensuche wiederholen oder eine Zwischenspeicherung durchführen müssen (zB im statischen Konstruktor für den generischen Typ, der die Methode enthält).