Was ich tun möchte, ist ungefähr so: Ich habe Aufzählungen mit kombinierten gekennzeichneten Werten.
public static class EnumExtension
{
public static bool IsSet<T>( this T input, T matchTo )
where T:enum //the constraint I want that doesn't exist in C#3
{
return (input & matchTo) != 0;
}
}
Also könnte ich tun:
MyEnum tester = MyEnum.FlagA | MyEnum.FlagB
if( tester.IsSet( MyEnum.FlagA ) )
//act on flag a
Leider ist C # generisch, wo Einschränkungen keine Aufzählungsbeschränkung haben, nur Klasse und Struktur. C # sieht Enums nicht als Strukturen (obwohl es sich um Werttypen handelt), daher kann ich solche Erweiterungstypen nicht hinzufügen.
Kennt jemand eine Problemumgehung?
struct
.Antworten:
BEARBEITEN: Dies ist jetzt live in Version 0.0.0.2 von UnconstrainedMelody.
(Wie in meinem Blog-Beitrag zu Aufzählungsbeschränkungen angefordert . Ich habe die folgenden grundlegenden Fakten hinzugefügt, um eine eigenständige Antwort zu erhalten.)
Die beste Lösung ist, darauf zu warten, dass ich es in UnconstrainedMelody 1 einbinde . Dies ist eine Bibliothek, die C # -Code mit "falschen" Einschränkungen wie z
und verwandelt es in
über einen Postbuild-Schritt.
Es sollte nicht zu schwer zu schreiben sein
IsSet
... obwohl es schwierig sein könnte, sowohl auf derInt64
Basis als auch auf derUInt64
Basis von Flags zu arbeiten. (Ich rieche einige Hilfsmethoden, die es mir ermöglichen, alle Flaggen so zu behandeln, als ob sie einen Basistyp hättenUInt64
.)Was möchten Sie, wenn Sie anrufen?
? Sollte überprüft werden, ob alle angegebenen Flags gesetzt sind? Das wäre meine Erwartung.
Ich werde versuchen, dies heute Abend auf dem Heimweg zu tun ... Ich hoffe, einen kurzen Einblick in nützliche Aufzählungsmethoden zu bekommen, um die Bibliothek schnell auf einen brauchbaren Standard zu bringen, und mich dann ein wenig zu entspannen.
EDIT: Ich bin mir
IsSet
übrigens nicht sicher , wie es heißt. Optionen:Gedanken willkommen. Ich bin mir sicher, dass es eine Weile dauern wird, bis irgendetwas in Stein gemeißelt ist ...
1 oder als Patch einreichen, natürlich ...
quelle
colors.HasAny(Colors.Red | Colors.Blue)
sieht aus wie sehr lesbarer Code.=)
where T : System.Enum
. Dies wurde bereits an anderer Stelle im Thread geschrieben; Ich dachte nur, ich würde es hier wiederholen.Ab C # 7.3 gibt es jetzt eine integrierte Möglichkeit, Enum-Einschränkungen hinzuzufügen:
Quelle: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint
quelle
Darren, das würde funktionieren, wenn die Typen bestimmte Aufzählungen wären - damit allgemeine Aufzählungen funktionieren, müssen Sie sie in Ints (oder wahrscheinlicher Uint) umwandeln, um die boolesche Mathematik durchzuführen:
quelle
Convert.ToUInt32
ich habe nirgendwo anders gefunden. AFAIK, es ist die einzige anständige Pre-Net-4-Lösung, die auch in VB funktioniert. Übrigens, wennmatchTo
möglicherweise mehrere Flag-Bits vorhanden sind, ersetzen Sie diese!= 0
durch== Convert.ToUInt32(matchTo)
.Convert.ToUInt32
Verwendung mit einer Aufzählung dieConvert.ToUInt32(object)
Überladung verwendet wird. Dies bedeutet, dass CLR diese Werte zuerst einschließt, bevor sie an dieToUInt32
Methode übergeben werden. In den meisten Fällen spielt dies keine Rolle, aber es ist gut zu wissen, dass Sie den GC ziemlich beschäftigt halten, wenn Sie so etwas verwenden, um Millionen von Aufzählungen pro Sekunde zu analysieren.Eigentlich ist es mit einem hässlichen Trick möglich. Es kann jedoch nicht für Erweiterungsmethoden verwendet werden.
Wenn Sie möchten, können Sie
Enums<Temp>
einen privaten Konstruktor und eine öffentlich verschachtelte abstrakte geerbte Klasse mitTemp
asEnum
angeben, um geerbte Versionen für Nicht-Enums zu verhindern.quelle
Sie können dies mit IL Weaving und ExtraConstraints erreichen
Ermöglicht das Schreiben dieses Codes
Was wird kompiliert
quelle
Ab C # 7.3 können Sie die Enum-Einschränkung für generische Typen verwenden:
Wenn Sie eine Nullable-Aufzählung verwenden möchten, müssen Sie die ursprüngliche Strukturbeschränkung beibehalten:
quelle
Dies beantwortet nicht die ursprüngliche Frage, aber in .NET 4 gibt es jetzt eine Methode namens Enum.HasFlag, die genau das tut, was Sie in Ihrem Beispiel versuchen
quelle
flag
. .NET 4.0 ist jetzt fünf Jahre alt.So wie ich es mache, wird eine Strukturbeschränkung gesetzt und dann überprüft, ob T zur Laufzeit eine Aufzählung ist. Dies beseitigt das Problem nicht vollständig, reduziert es jedoch etwas
quelle
Mit Ihrem Originalcode können Sie innerhalb der Methode auch die Reflexion verwenden, um zu testen, ob T eine Aufzählung ist:
quelle
Hier ist ein Code, den ich gerade erstellt habe und der so zu funktionieren scheint, wie Sie es möchten, ohne etwas zu Verrücktes tun zu müssen. Es ist nicht nur auf Aufzählungen beschränkt, die als Flags festgelegt sind, sondern es kann bei Bedarf immer ein Scheck eingefügt werden.
quelle
Wenn jemand generisches IsSet benötigt (das sofort im laufenden Betrieb erstellt werden könnte, könnte verbessert werden) und / oder eine Konvertierung von Zeichenfolge in Enum onfly (die die unten dargestellte EnumConstraint verwendet):
Wenn jemand noch ein heißes Beispiel benötigt, um eine Enum-Codierungsbeschränkung zu erstellen:
hoffe das hilft jemandem.
quelle
Ich wollte nur Enum als generische Einschränkung hinzufügen.
Dies ist zwar nur für eine winzige Hilfsmethode gedacht
ExtraConstraints
ist die für mich etwas zu viel Aufwand.Ich habe mich entschieden, einfach eine
struct
Einschränkung zu erstellen und eine Laufzeitprüfung für hinzuzufügenIsEnum
. Um eine Variable von T nach Enum zu konvertieren, habe ich sie zuerst in ein Objekt umgewandelt.quelle