2011-01-17 1 views

Antwort

13

EDIT: I dachte das war Teil von ECMA 335, aber ich kann es nirgendwo dort sehen.

Sie können nicht einen solchen Delegattyp in C# erstellen, aber Sie können in IL:

.class public auto ansi sealed Foo 
     extends [mscorlib]System.Delegate 
{ 
    // Body as normal 
} 

Der C# Compiler hat keine Probleme unter Verwendung eines solchen Delegierten:

using System; 

class Test 
{ 
    static void Main() 
    { 
     Foo f = x => Console.WriteLine(x); 
     f("hello"); 
    } 
} 

Aber die CLR tut es, wenn es versucht, es zu laden:

Nicht behandelte Ausnahme: System.TypeLoadException: konnte Typ "Foo" von Assembly nicht laden "Foo, Version = 0.0.0.0, Culture = neutral, PublicKeyToken = null ', da es nicht direkt von der Delegate-Klasse erben kann. bei Test.Main()

Grundsätzlich ist die Delegate/MulticastDelegate-Trennung ein historischer Unfall. Ich glaube, dass frühe Alpha/Beta-Versionen die Unterscheidung machten, aber es erwies sich als zu verwirrend und im Allgemeinen nicht nützlich - so dass nun alle Delegaten von MulticastDelegate abgeleitet sind.

(Interessanterweise ist die C# Spezifikation erwähnt nur einmal MulticastDelegate, die in der Liste der Typen können nicht als generische Einschränkungen verwendet werden.)

+0

Was sagt PEVerify zu dieser Versammlung mit 'Foo'? – leppie

+0

@leppie: Hab noch nicht probiert. Fühlen Sie sich frei, dies zu tun :) (Ich lief nur ildasm auf eine "normale" Erklärung, um die IL zu bekommen, dann drafted es und re-ilasmed.) –

+0

Ich verwendete ilasm/ildasm zu einem Testdelegierten und bekam das erwartete Ergebnis in Ihrer Antwort . Vielen Dank. –

1

Nein, die CLR erlaubt das nicht.

Ich erinnere mich an etwas, das sie Delegate direkt aussetzen wollten, aber das wurde nie benötigt.

2

Nein, es gibt nicht, weil alle Delegierten natürlich Delegate.Combine ed sein können. Delegierter ist es einfach, die Nicht-Multicasting-Funktionalität in eine Basisklasse zu verpacken.

+0

Auch wenn jeder Delegat einen einzigen Methodenzeiger und ein Ziel hatte, konnte Delegate.Combine einfach implementiert werden: Erstellen Sie einfach ein Objekt mit zwei Feldern des entsprechenden Delegattyps, der sie nacheinander ausführt. Die Verwendung von MulticastDelegates kann in Situationen, in denen Delegierte mit einer großen Anzahl von Unterdelegierten häufig, aber selten mit Combine und Remove beschäftigt sind, einen Leistungsvorteil bieten, aber ich würde mich wundern, wenn dies in typischen Situationen zu einer besseren Leistung führt. Persönlich wünschte ich mir, dass es einen änderbaren "Ereignislisten" -Typ gegeben hätte, vielleicht eine Struktur mit einem einzelnen Feld ... – supercat

+0

... vom Typ Object, das entweder eine Null, einen einzelnen Delegaten oder ein Array von Delegierten enthalten könnte und die Methoden zum Aufrufen dieses Feldes sowie thread-sichere Add- und Remove-Operationen (mit Interlocked) enthalten.VergleichenExchange); Die Aufrufmethoden sollten die Möglichkeit bieten, bei der ersten Ausnahme anzuhalten oder alle Handler ausführen zu lassen und eine BundledException mit einer Liste aller während ihrer Ausführung aufgetretenen Ausnahmen zu werfen. Wenn die Ereignisliste statt einer Liste von Methoden und Zielen Delegiertenverweise enthält, werden Macken im bestehenden Ansatz beseitigt. – supercat

2

System.MuticastDelegate von System.Delegate abgeleitet ist. Jede Ebene in der Delegatenhierarchie stellt eine andere Gruppe von Diensten bereit. System.Delegate ist ein Container mit den Daten für welche Methode ein bestimmtes Objekt aufgerufen werden soll. Mit System.MulticastDelegate können Sie nicht nur eine Methode für ein einzelnes Objekt, sondern für eine Objektgruppe aufrufen. Dies ermöglicht mehrere Abonnenten für ein Ereignis.

Nicht sicher, ich habe Ihre Frage beantwortet.

+2

Während das klingt angemessen, es erklärt nicht, warum GetInvocationList (eindeutig über das Aufrufen von * multiple * Methoden) Teil des Delegate ist, und nicht MulticastDelegate ... –