Mir ist völlig klar, dass das, was ich vorschlage, nicht den .NET-Richtlinien entspricht und daher wahrscheinlich allein aus diesem Grund eine schlechte Idee ist. Ich möchte dies jedoch aus zwei möglichen Perspektiven betrachten:
(1) Sollte ich in Betracht ziehen, dies für meine eigene Entwicklungsarbeit zu verwenden, die zu 100% für interne Zwecke bestimmt ist?
(2) Ist dies ein Konzept, das die Framework-Designer ändern oder aktualisieren könnten?
Ich denke darüber nach, eine Ereignissignatur zu verwenden, die einen stark typisierten "Absender" verwendet, anstatt ihn als "Objekt" zu tippen, was das aktuelle .NET-Entwurfsmuster ist. Das heißt, anstatt eine Standardereignissignatur zu verwenden, die folgendermaßen aussieht:
class Publisher
{
public event EventHandler<PublisherEventArgs> SomeEvent;
}
Ich erwäge die Verwendung einer Ereignissignatur, die einen stark typisierten Absenderparameter verwendet, wie folgt:
Definieren Sie zunächst einen "StrongTypedEventHandler":
[SerializableAttribute]
public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
Dies unterscheidet sich nicht allzu sehr von einer Aktion <TSender, TEventArgs>, aber durch die Verwendung von StrongTypedEventHandler
erzwingen wir, dass die TEventArgs von abgeleitet sind System.EventArgs
.
Als nächstes können wir als Beispiel den StrongTypedEventHandler in einer Publishing-Klasse wie folgt verwenden:
class Publisher
{
public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;
protected void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent(this, new PublisherEventArgs(...));
}
}
}
Die obige Anordnung würde es Abonnenten ermöglichen, einen stark typisierten Ereignishandler zu verwenden, für den kein Casting erforderlich ist:
class Subscriber
{
void SomeEventHandler(Publisher sender, PublisherEventArgs e)
{
if (sender.Name == "John Smith")
{
// ...
}
}
}
Mir ist völlig klar, dass dies mit dem Standardmuster für die Behandlung von .NET-Ereignissen bricht. Beachten Sie jedoch, dass ein Abonnent durch Kontravarianz auf Wunsch eine herkömmliche Signatur für die Ereignisbehandlung verwenden kann:
class Subscriber
{
void SomeEventHandler(object sender, PublisherEventArgs e)
{
if (((Publisher)sender).Name == "John Smith")
{
// ...
}
}
}
Das heißt, wenn ein Ereignishandler Ereignisse von unterschiedlichen (oder möglicherweise unbekannten) Objekttypen abonnieren muss, kann der Handler den Parameter 'sender' als 'object' eingeben, um die gesamte Breite potenzieller Absenderobjekte zu verarbeiten.
Abgesehen davon, dass ich gegen die Konvention verstoße (was ich nicht leicht nehme, glauben Sie mir), kann ich mir keine Nachteile vorstellen.
Hier können einige CLS-Konformitätsprobleme auftreten. Dies läuft in Visual Basic .NET 2008 zu 100% in Ordnung (ich habe es getestet), aber ich glaube, dass die älteren Versionen von Visual Basic .NET bis 2005 keine delegierte Kovarianz und Kontravarianz aufweisen. [Bearbeiten: Ich habe dies seitdem getestet und es wurde bestätigt: VB.NET 2005 und niedriger können dies nicht verarbeiten, aber VB.NET 2008 ist zu 100% in Ordnung. Siehe "Bearbeiten # 2" weiter unten.] Möglicherweise gibt es andere .NET-Sprachen, bei denen ebenfalls ein Problem auftritt. Ich kann nicht sicher sein.
Ich sehe mich jedoch nicht für eine andere Sprache als C # oder Visual Basic .NET entwickelt, und es macht mir nichts aus, sie auf C # und VB.NET für .NET Framework 3.0 und höher zu beschränken. (Ich könnte mir nicht vorstellen, zu diesem Zeitpunkt auf 2.0 zurückzukehren, um ehrlich zu sein.)
Kann sich noch jemand ein Problem damit vorstellen? Oder bricht dies einfach so sehr mit der Konvention, dass sich die Mägen der Menschen drehen?
Hier sind einige verwandte Links, die ich gefunden habe:
(1) Richtlinien für das Event-Design [MSDN 3.5]
(3) Ereignissignaturmuster in .net [StackOverflow 2008]
Ich interessiere mich für jedermanns und jedermanns Meinung dazu ...
Danke im Voraus,
Mike
Edit # 1: Dies ist eine Antwort auf den Beitrag von Tommy Carlier :
Hier ist ein voll funktionsfähiges Beispiel, das zeigt, dass sowohl stark typisierte Ereignishandler als auch die aktuellen Standardereignishandler, die einen Parameter "Objektabsender" verwenden, mit diesem Ansatz koexistieren können. Sie können den Code kopieren, einfügen und ausführen:
namespace csScrap.GenericEventHandling
{
class PublisherEventArgs : EventArgs
{
// ...
}
[SerializableAttribute]
public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
class Publisher
{
public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;
public void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent(this, new PublisherEventArgs());
}
}
}
class StrongTypedSubscriber
{
public void SomeEventHandler(Publisher sender, PublisherEventArgs e)
{
MessageBox.Show("StrongTypedSubscriber.SomeEventHandler called.");
}
}
class TraditionalSubscriber
{
public void SomeEventHandler(object sender, PublisherEventArgs e)
{
MessageBox.Show("TraditionalSubscriber.SomeEventHandler called.");
}
}
class Tester
{
public static void Main()
{
Publisher publisher = new Publisher();
StrongTypedSubscriber strongTypedSubscriber = new StrongTypedSubscriber();
TraditionalSubscriber traditionalSubscriber = new TraditionalSubscriber();
publisher.SomeEvent += strongTypedSubscriber.SomeEventHandler;
publisher.SomeEvent += traditionalSubscriber.SomeEventHandler;
publisher.OnSomeEvent();
}
}
}
Edit # 2: Dies ist eine Antwort auf Andrew Hares Aussage bezüglich Kovarianz und Kontravarianz und wie sie hier gilt. Delegierte in der C # -Sprache hatten so lange Kovarianz und Kontravarianz, dass es sich nur "intrinsisch" anfühlt, aber nicht. Ich weiß nicht, dass es möglicherweise sogar in der CLR aktiviert ist, aber Visual Basic .NET hat für seine Delegaten erst mit .NET Framework 3.0 (VB.NET 2008) Kovarianz- und Kontravarianzfunktionen erhalten. Infolgedessen kann Visual Basic.NET für .NET 2.0 und niedriger diesen Ansatz nicht verwenden.
Das obige Beispiel kann beispielsweise wie folgt in VB.NET übersetzt werden:
Namespace GenericEventHandling
Class PublisherEventArgs
Inherits EventArgs
' ...
' ...
End Class
<SerializableAttribute()> _
Public Delegate Sub StrongTypedEventHandler(Of TSender, TEventArgs As EventArgs) _
(ByVal sender As TSender, ByVal e As TEventArgs)
Class Publisher
Public Event SomeEvent As StrongTypedEventHandler(Of Publisher, PublisherEventArgs)
Public Sub OnSomeEvent()
RaiseEvent SomeEvent(Me, New PublisherEventArgs)
End Sub
End Class
Class StrongTypedSubscriber
Public Sub SomeEventHandler(ByVal sender As Publisher, ByVal e As PublisherEventArgs)
MessageBox.Show("StrongTypedSubscriber.SomeEventHandler called.")
End Sub
End Class
Class TraditionalSubscriber
Public Sub SomeEventHandler(ByVal sender As Object, ByVal e As PublisherEventArgs)
MessageBox.Show("TraditionalSubscriber.SomeEventHandler called.")
End Sub
End Class
Class Tester
Public Shared Sub Main()
Dim publisher As Publisher = New Publisher
Dim strongTypedSubscriber As StrongTypedSubscriber = New StrongTypedSubscriber
Dim traditionalSubscriber As TraditionalSubscriber = New TraditionalSubscriber
AddHandler publisher.SomeEvent, AddressOf strongTypedSubscriber.SomeEventHandler
AddHandler publisher.SomeEvent, AddressOf traditionalSubscriber.SomeEventHandler
publisher.OnSomeEvent()
End Sub
End Class
End Namespace
VB.NET 2008 kann zu 100% ausgeführt werden. Aber ich habe es jetzt auf VB.NET 2005 getestet, nur um sicherzugehen, und es wird nicht kompiliert.
Die Methode 'Public Sub SomeEventHandler (Absender als Objekt, e als vbGenericEventHandling.GenericEventHandling.PublisherEventArgs)' hat nicht dieselbe Signatur wie der Delegat 'Delegate Sub StrongTypedEventHandler (von TSender, TEventArgs als System.EventArgs) (Absender als Herausgeber, e als PublisherEvent) '
Grundsätzlich sind Delegaten in VB.NET-Versionen 2005 und niedriger unveränderlich. Ich habe vor ein paar Jahren tatsächlich an diese Idee gedacht, aber die Unfähigkeit von VB.NET, damit umzugehen, hat mich gestört ... Aber ich bin jetzt fest zu C # übergegangen, und VB.NET kann jetzt damit umgehen dieser Beitrag.
Bearbeiten: Update # 3
Ok, ich benutze das jetzt schon eine Weile ziemlich erfolgreich. Es ist wirklich ein schönes System. Ich habe beschlossen, meinen "StrongTypedEventHandler" als "GenericEventHandler" zu bezeichnen, der wie folgt definiert ist:
[SerializableAttribute]
public delegate void GenericEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
Abgesehen von dieser Umbenennung habe ich sie genau wie oben beschrieben implementiert.
Es wird über die FxCop-Regel CA1009 ausgelöst, die besagt:
"Konventionell haben .NET-Ereignisse zwei Parameter, die den Ereignisabsender und die Ereignisdaten angeben. Ereignishandlersignaturen sollten folgendermaßen aussehen: void MyEventHandler (Objektabsender, EventArgs e). Der Parameter 'sender' ist immer vom Typ System.Object, Selbst wenn es möglich ist, einen spezifischeren Typ zu verwenden. Der Parameter 'e' ist immer vom Typ System.EventArgs. Ereignisse, die keine Ereignisdaten bereitstellen, sollten den Delegatentyp System.EventHandler verwenden. Ereignishandler geben void zurück, damit sie senden können jedes Ereignis an mehrere Zielmethoden. Jeder von einem Ziel zurückgegebene Wert geht nach dem ersten Aufruf verloren. "
Natürlich wissen wir das alles und brechen trotzdem die Regeln. (Alle Ereignishandler können in jedem Fall den Standard-Objektabsender in ihrer Signatur verwenden, wenn dies bevorzugt wird. Dies ist eine unveränderliche Änderung.)
Die Verwendung von a SuppressMessageAttribute
macht also den Trick:
[SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly",
Justification = "Using strong-typed GenericEventHandler<TSender, TEventArgs> event handler pattern.")]
Ich hoffe, dass dieser Ansatz irgendwann in der Zukunft zum Standard wird. Es funktioniert wirklich sehr gut.
Vielen Dank für all Ihre Meinungen, Leute, ich weiß das wirklich zu schätzen ...
Mike
oh hi this my hom work solve it plz :code dump:
Fragen in Tweet-Größe , sondern eine Frage , aus der wir lernen .
EventHandler<,>
als GenericEventHandler<,>
. EventHandler<>
In BCL gibt es bereits Generika, die nur EventHandler heißen. EventHandler ist also ein gebräuchlicherer Name und Delegierte unterstützen