私が提案しているものは.NETガイドラインに従っていないことを十分に理解しているため、この理由だけではおそらくあまり良い考えではありません。ただし、これを2つの考えられる観点から検討したいと思います。
(1)これを自分の開発作業に使用することを検討する必要があります。これは内部目的のために100%です。
(2)これは、フレームワーク設計者が変更または更新を検討できる概念ですか?
現在の.NETデザインパターンである「オブジェクト」として入力するのではなく、厳密に型指定された「送信者」を使用するイベントシグネチャを使用することを考えています。つまり、次のような標準のイベントシグネチャを使用する代わりに、
class Publisher
{
public event EventHandler<PublisherEventArgs> SomeEvent;
}
次のように、厳密に型指定された「送信者」パラメータを使用するイベントシグネチャの使用を検討しています。
まず、「StrongTypedEventHandler」を定義します。
[SerializableAttribute]
public delegate void StrongTypedEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
これはAction <TSender、TEventArgs>とそれほど異なるわけではありませんが、を利用するStrongTypedEventHandler
ことで、TEventArgsがから派生することを強制しSystem.EventArgs
ます。
次に、例として、次のように発行クラスでStrongTypedEventHandlerを利用できます。
class Publisher
{
public event StrongTypedEventHandler<Publisher, PublisherEventArgs> SomeEvent;
protected void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent(this, new PublisherEventArgs(...));
}
}
}
上記の配置により、サブスクライバーはキャストを必要としない厳密に型指定されたイベントハンドラーを利用できるようになります。
class Subscriber
{
void SomeEventHandler(Publisher sender, PublisherEventArgs e)
{
if (sender.Name == "John Smith")
{
// ...
}
}
}
これが標準の.NETイベント処理パターンで壊れることを私は完全に理解しています。ただし、必要に応じて、逆分散により、サブスクライバーが従来のイベント処理シグネチャを使用できるようになることに注意してください。
class Subscriber
{
void SomeEventHandler(object sender, PublisherEventArgs e)
{
if (((Publisher)sender).Name == "John Smith")
{
// ...
}
}
}
つまり、イベントハンドラーが異種の(またはおそらく不明な)オブジェクトタイプからイベントをサブスクライブする必要がある場合、ハンドラーは、潜在的な送信者オブジェクトの全範囲を処理するために、「送信者」パラメーターを「オブジェクト」として入力できます。
慣習を破る以外は(これは軽んじることではありませんが、信じてください)、これの欠点は考えられません。
ここにCLS準拠の問題があるかもしれません。これはVisual Basic .NET 2008で100%正常に動作します(私はテストしました)が、2005までの古いバージョンのVisual Basic .NETにはデリゲートの共分散と反分散がないと思います。[編集:私はこれをテストして確認しました。VB.NET2005以前ではこれを処理できませんが、VB.NET 2008は100%正常です。以下の「編集#2」を参照してください。]他の.NET言語でもこの問題が発生している可能性があります。
しかし、私はC#またはVisual Basic .NET以外の言語で開発しているようには見えません。また、それを.NET Framework 3.0以降のC#およびVB.NETに制限してもかまいません。(正直に言うと、この時点で2.0に戻ることは想像できませんでした。)
他の誰かがこれの問題について考えることができますか?それとも、これは単に慣習で破られて、人々の腹を回すだけですか?
ここに私が見つけたいくつかの関連リンクがあります:
(2)C#の単純なイベント発生-「送信者」とカスタムEventArgsの使用[StackOverflow 2009]
(3).netのイベント署名パターン[StackOverflow 2008]
私はこれについて誰かの意見や誰の意見にも興味があります...
前もって感謝します、
マイク
編集#1:これは、Tommy Carlierの投稿への返信です。
以下は、厳密に型指定されたイベントハンドラーと、 'オブジェクト送信者'パラメーターを使用する現在の標準イベントハンドラーの両方がこのアプローチと共存できることを示す完全に機能する例です。コードにコピーして貼り付け、実行することができます:
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();
}
}
}
編集#2:これは、共分散と反変に関するAndrew Hareの声明、およびここでの適用方法に対応しています。C#言語のデリゲートには共分散と反変があり、「内在的」と感じるだけですが、そうではありません。CLRで有効になっているものかもしれませんが、Visual Basic .NETは、.NET Framework 3.0(VB.NET 2008)まで、デリゲートの共分散機能と反変機能を備えていませんでした。その結果、Visual Basic.NET for .NET 2.0以前では、このアプローチを利用できません。
たとえば、上記の例は次のようにVB.NETに変換できます。
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は100%正常に実行できます。しかし、念のためVB.NET 2005でテストしましたが、コンパイルできません。
メソッド 'Public Sub SomeEventHandler(sender As Object、e As vbGenericEventHandling.GenericEventHandling.PublisherEventArgs)'には、デリゲート 'Delegate Sub StrongTypedEventHandler(Of TSender、TEventArgs As System.EventArgs)(sender As Publisher、e As PublisherEventArgs)と同じシグネチャがありません」
基本的に、デリゲートはVB.NETバージョン2005以下では不変です。私は数年前にこの考えを実際に考えましたが、VB.NETがこれに対処できないことは私を悩ませていました...しかし、今ではしっかりとC#に移行し、VB.NETはそれを処理できるようになりました。この郵便受け。
編集:更新#3
わかりました、私はこれをしばらくの間かなりうまく使用しています。それは本当に素晴らしいシステムです。私は "StrongTypedEventHandler"に "GenericEventHandler"という名前を付けることにしました。これは次のように定義されています。
[SerializableAttribute]
public delegate void GenericEventHandler<TSender, TEventArgs>(
TSender sender,
TEventArgs e
)
where TEventArgs : EventArgs;
この名前の変更以外は、上で説明したとおりに実装しました。
FxCopルールCA1009をトリップします。
「慣例として、.NETイベントには、イベント送信者とイベントデータを指定する2つのパラメーターがあります。イベントハンドラーのシグネチャは、次の形式に従う必要があります:void MyEventHandler(object sender、EventArgs e)。より具体的なタイプを使用することも可能です。「e」パラメーターは常にタイプSystem.EventArgsです。イベントデータを提供しないイベントは、System.EventHandlerデリゲートタイプを使用する必要があります。イベントハンドラーはvoidを返して送信できるようにします各イベントを複数のターゲットメソッドに送信します。ターゲットから返された値は、最初の呼び出し後に失われます。」
もちろん、私たちはこれらすべてを知っており、とにかくルールを破っています。(いずれの場合でも、すべてのイベントハンドラーは、必要に応じて、標準の「オブジェクト送信者」をシグネチャで使用できます。これは、互換性を保つための変更です。)
したがって、aを使用するとSuppressMessageAttribute
うまくいきます。
[SuppressMessage("Microsoft.Design", "CA1009:DeclareEventHandlersCorrectly",
Justification = "Using strong-typed GenericEventHandler<TSender, TEventArgs> event handler pattern.")]
このアプローチが将来の標準になることを願っています。それは本当にとてもうまくいきます。
みなさん、ありがとうございました。本当に感謝しています...
マイク
oh hi this my hom work solve it plz :code dump:
質問の1つではなく、私たちから学んだ質問です。
EventHandler<,>
よりもGenericEventHandler<,>
。EventHandler<>
EventHandlerという名前のBCLにはすでにジェネリックがあります。したがって、EventHandlerはより一般的な名前であり、デリゲートは型のオーバーロードをサポートしています