Ist es möglich, eine Klasse in C # so zu definieren, dass
class GenericCollection<T> : SomeBaseCollection<T> where T : Delegate
Ich konnte diese letzte Nacht in .NET 3.5 für mein ganzes Leben nicht erreichen. Ich habe es versucht
delegate, Delegate, Action<T> and Func<T, T>
Es scheint mir, dass dies in irgendeiner Weise zulässig sein sollte. Ich versuche meine eigene EventQueue zu implementieren.
Am Ende habe ich nur dies getan [wohlgemerkt primitive Annäherung].
internal delegate void DWork();
class EventQueue {
private Queue<DWork> eventq;
}
Aber dann verliere ich die Fähigkeit, dieselbe Definition für verschiedene Arten von Funktionen wiederzuverwenden.
Gedanken?
CA1065: Do not raise exceptions in unexpected locations
... Ich war immer unter der Annahme, dass Sie eine benutzerdefinierte Code-Analyseregel verwenden sollten, um ungültige Verwendungen Ihrer Klasse zu finden, die normalerweise zur Laufzeit nicht verfügbar sind.where T : Delegate
werden (und jemand hat unten eine neue Antwort dazu gepostet).Ja , es ist möglich , in C # 7.3, Constraints Familie gehört erhöht
Enum
,Delegate
undunmanaged
Typen. Sie können diesen Code problemlos schreiben:void M<D, E, T>(D d, E e, T* t) where D : Delegate where E : Enum where T : unmanaged { }
Aus Dokumenten :
Nützliche Links:
Die Zukunft von C # aus Microsoft Build 2018
Was ist neu in C # 7.3?
quelle
Bearbeiten: In diesen Artikeln werden einige vorgeschlagene Problemumgehungen vorgeschlagen:
http://jacobcarpenters.blogspot.com/2006/06/c-30-and-delegate-conversion.html
http://jacobcarpenters.blogspot.com/2006_11_01_archive.html
Aus der C # 2.0-Spezifikation können wir lesen (20.7, Constraints):
Eine Einschränkung vom Typ Klasse muss die folgenden Regeln erfüllen:
Und sicher spuckt VS2008 einen Fehler aus:
error CS0702: Constraint cannot be special class 'System.Delegate'
Informationen und Informationen zu diesem Thema finden Sie hier .
quelle
Wenn Sie bereit sind, eine Kompilierungszeitabhängigkeit von einem IL Weaver zu übernehmen, können Sie dies mit Fody tun .
Verwenden dieses Add-Ins zu Fody https://github.com/Fody/ExtraConstraints
Ihr Code kann so aussehen
public class Sample { public void MethodWithDelegateConstraint<[DelegateConstraint] T> () { } public void MethodWithEnumConstraint<[EnumConstraint] T>() { } }
Und dazu zusammengestellt werden
public class Sample { public void MethodWithDelegateConstraint<T>() where T: Delegate { } public void MethodWithEnumConstraint<T>() where T: struct, Enum { } }
quelle
Der Delegat unterstützt bereits die Verkettung. Entspricht das nicht Ihren Bedürfnissen?
public class EventQueueTests { public void Test1() { Action myAction = () => Console.WriteLine("foo"); myAction += () => Console.WriteLine("bar"); myAction(); //foo //bar } public void Test2() { Action<int> myAction = x => Console.WriteLine("foo {0}", x); myAction += x => Console.WriteLine("bar {0}", x); myAction(3); //foo 3 //bar 3 } public void Test3() { Func<int, int> myFunc = x => { Console.WriteLine("foo {0}", x); return x + 2; }; myFunc += x => { Console.WriteLine("bar {0}", x); return x + 1; }; int y = myFunc(3); Console.WriteLine(y); //foo 3 //bar 3 //4 } public void Test4() { Func<int, int> myFunc = x => { Console.WriteLine("foo {0}", x); return x + 2; }; Func<int, int> myNextFunc = x => { x = myFunc(x); Console.WriteLine("bar {0}", x); return x + 1; }; int y = myNextFunc(3); Console.WriteLine(y); //foo 3 //bar 5 //6 } }
quelle
Ich stieß auf eine Situation, in der ich mich
Delegate
intern mit einem Problem befassen musste, aber ich wollte eine generische Einschränkung. Insbesondere wollte ich einen Ereignishandler mithilfe von Reflection hinzufügen, aber ich wollte ein generisches Argument für den Delegaten verwenden. Der folgende Code funktioniert NICHT, da "Handler" eine Typvariable ist und der Compiler nichtHandler
in Folgendes umwandeltDelegate
:public void AddHandler<Handler>(Control c, string eventName, Handler d) { c.GetType().GetEvent(eventName).AddEventHandler(c, (Delegate) d); }
Sie können jedoch eine Funktion übergeben, die die Konvertierung für Sie durchführt.
convert
nimmt einHandler
Argument und gibt einDelegate
:public void AddHandler<Handler>(Control c, string eventName, Func<Delegate, Handler> convert, Handler d) { c.GetType().GetEvent(eventName).AddEventHandler(c, convert(d)); }
Jetzt ist der Compiler glücklich. Das Aufrufen der Methode ist einfach. Beispiel: Anhängen an das
KeyPress
Ereignis in einem Windows Forms-Steuerelement:AddHandler<KeyEventHandler>(someControl, "KeyPress", (h) => (KeyEventHandler) h, SomeControl_KeyPress);
Wo
SomeControl_KeyPress
ist das Ereignisziel? Der Schlüssel ist der Konverter Lambda - er funktioniert nicht, überzeugt aber den Compiler, den Sie ihm als gültigen Delegaten gegeben haben.(Beginnen Sie mit 280Z28) @Justin: Warum nicht?
public void AddHandler<Handler>(Control c, string eventName, Handler d) { c.GetType().GetEvent(eventName).AddEventHandler(c, d as Delegate); }
(Ende 280Z28)
quelle
Wie oben erwähnt, können Sie Delegates und Enum nicht als allgemeine Einschränkung verwenden.
System.Object
undSystem.ValueType
kann auch nicht als generische Einschränkung verwendet werden.Die Problemumgehung kann sein, wenn Sie in Ihrer IL einen entsprechenden Aufruf erstellen. Es wird gut funktionieren.
Hier ist ein gutes Beispiel von Jon Skeet.
http://code.google.com/p/unconstrained-melody/
Ich habe meine Referenzen aus Jon Skeets Buch C # in Depth , 3. Auflage, entnommen .
quelle
Laut MSDN
Compilerfehler CS0702
Einschränkung kann keine spezielle Klassen-ID sein. Die folgenden Typen dürfen nicht als Einschränkungen verwendet werden:
quelle