web-dev-qa-db-ja.com

イベントハンドラーの戻り値の型が常にvoidであるのはなぜですか?

ねえ、なぜ次のようなイベントの戻り値の型なのか疑問に思いました

private void button1_Click(object sender, EventArgs e)

常に無効ですか?

他の値も返すことができますか?

25
smriti

イベントハンドラのシグネチャ、つまり戻り値の型とそれが取る引数の数とタイプは、イベントを定義するために使用されるdelegateのシグネチャによって決定されます。したがって、例のボタンのClickイベントは、戻り値をサポートしていません。

通常、イベントは複数のサブスクライバーを持つことができ、それぞれが他のハンドラーとは独立して戻り値を返し、何を行うかを決定するために特別なイベント発生コードが必要になるため、イベントハンドラーから値を関数の戻り値として返すことは期待できません。すべての戻り値を処理します。

通常、イベントハンドラーから通信する必要がある場合、EventArgs構造にはハンドラーが更新できるメンバーが含まれ、各ハンドラーは値を確認してそれに応じて更新する機会を取得し、イベントを発生させるコードはそれに反応するだけで済みます。構造体の最終値。

35
Chris Taylor

イベントcanには戻り値があります。ただし、voidを返す(および2つのパラメーターを持つ)のはBCLガイドラインです。

イベントのマルチキャストプロパティを使用する場合、値を返すことは少し混乱します。戻り値は、実行されたlastハンドラーの値です。サブスクライブされた他のすべてのハンドラーの戻り値は失われます。また、イベントはデカップリングに使用されるため、イベントが実行される順序をあまり制御できません。これにより、戻り値は非常に実用的ではなくなります。

EventArgsの子孫の書き込み可能なプロパティ(たとえば、Window.ClosingイベントのCancelプロパティ)を介して情報を共有および返すことは、別のBCLプラクティスです。すべてのハンドラーがこれを表示および変更できます。それでも最後の1つが勝つソリューションですが、より優れています。

しかし、それをすべて言っても、あなたはまだ書くことができます:

delegate int Summer(int[] arr);  // delegate

class Program
{
    public event Summer OnSum;   // event

    void DoSum()
    {
        int[] data = {1, 2, 3} ;              
        int sum = 0;

        if (OnSum != null)  
          sum = OnSum(data);   // execute it.
    }
}
17
Henk Holterman

.NETが標準コントロールのイベントに特定の署名を期待しているという事実とは別に、これを考慮してください。イベントには複数のイベントハンドラーをアタッチできますが、どの戻り値が使用されますか?

イベントハンドラが値を返すことは意味がありません。通常、これらはEventArgsから派生したオブジェクトの状態を変更して、イベントを発生させたものに何かを返します。

9
Thorarin

C#では、イベントには2つのタイプがあります

1。マルチキャスト
2。 UnitCast

マルチキャストイベントは、複数のサブスクライバーがいるイベントです。マルチキャストイベントが発生すると、複数のイベントハンドラーをサブスクライブしているため、複数のハンドラーが呼び出されます。 したがって、マルチキャストイベントは複数のハンドラーを呼び出すために使用されることを意図しており、マルチキャストハンドラーは戻り値の型を持つことができないのはなぜですか??

マルチキャストデリゲートに戻り値の型がある場合、すべてのイベントハンドラーが何らかの値を返し、1つのイベントハンドラーの戻り値が次のイベントハンドラー値に置き換えられるためです。

次のようなマルチキャストデリゲートがあるとします。

public delegate int buttonClick;

public event buttonClick onClick;

onClick += method1
onclick += method2
onclick += metho3

このイベントが発生すると、method1によって返される値は、method2によって返される値に置き換えられ、最終的にはmethod3のみの値が受信されます。

したがって、マルチキャストデリゲートの場合は、値を返さないことを常にお勧めします。

ただし、サブスクライバーが1つしかないユニキャスト委任の場合。したがって、目的を達成するために値を返すことができます

したがって、マルチキャストデリゲートの場合-戻り値の型なし、ユニキャストデリゲートの場合-戻り値の型を持つことができます

マルチキャストデリゲートは複数の値を返すこともできますが、そのイベントでは手動で発生させる必要があります。

マルチキャストデリゲートも値を返すように選択した場合のイベント。たとえば、4つのイベントハンドラーにバインドされ、2つの整数を取り、1つのハンドラーが加算、2番目の減算、3番目の乗算、最後の除算を行うイベントがあるとします。したがって、すべてのハンドラーの戻り値の型を取得する場合は、次の方法でイベントを手動で発生させる必要があります。

var handler = _eventToRaised.GetInvocationList();
foreach(var handler in handlers)
{
  if(handler != null)
   {
    var returnValue = handler()// pass the values which delegate expects.
   }

}
6
Yogesh

イベントを処理するデリゲートが特定の署名を予期しているため、これを行うことはできません(変更しようとすると、コンパイルエラーが発生します)。たとえば、この場合のデリゲート( Button.Click )は System.EventHandler 、デリゲートとしてコンパイル/機能するには、その署名と一致する必要があります。

public delegate void EventHandler(Object sender, EventArgs e)

これは、デリゲートがどのように機能するかを示しています。通常がどのように使用されているかを見ると、より理にかなっています。

MyButton.Click += button1_Click;

他に何か返品した場合...それは何に使用されますか?結果を返す何かを呼び出すつもりなら...それがメソッドの目的であり、EventHandlerではありません:)

5
Nick Craver

確かに、イベントcan戻り値。

   [TestClass]
   public class UnitTest1 {
      delegate int EventWithReturnValue();

      class A {
         public event EventWithReturnValue SomeEvent;
         public int LastEventResult { get; set; }

         public void RaiseEvent() {
            LastEventResult = SomeEvent();
         }
      }

      [TestMethod]
      public void TestMethod1() {
         A a = new A();
         a.SomeEvent += new EventWithReturnValue(a_SomeEvent);
         a.RaiseEvent();
         Assert.AreEqual(123, a.LastEventResult);
      }

      int a_SomeEvent() {
         return 123;
      }
   }

ただし、イベントの戻り値を使用してコンポーネントとそのコンシューマーの間で情報を交換することはあまり一般的ではありません。

5
Florian Reischl

多くの人々がすでにこれを制約ではなく慣習であると述べているように。 EventArgs自体の中でイベントに物を返すようにすることができます。 Microsoftはこのパターンを多くの場所で使用しています。WinFormsのFormClosingイベントを参照してください。したがって、値を返したい場合は、次のようにします。

public class AllowCloseEventArgs : EventArgs
{
    public bool AllowClose = true;
}

public void AllowClose(object sender, AllowCloseEventArgs e)
{ e.AllowClose = false; }

これを知ったところで、設計者がイベントの「標準」ボイドリターンプロトタイプを選択した理由について説明しましょう。

  1. 戻り値がある場合、どのタイプになりますか?
  2. イベントが値を返した場合、その値はどういう意味ですか?
  3. 戻り値の型がないため、イベントは一方向になります。つまり、例外を気にしない場合は、Control.BeginInvoke(...)を呼び出すようにイベントを「起動して忘れる」ことができます。

更新:ベンは正しく追加します:#4:イベントが複数の値を返す必要がある場合はどうなりますか?

3
csharptest.net

デフォルトのEventHandlerデリゲートがこの署名を定義しました。ただし、必要に応じて、独自の戻り値の型を使用して独自のイベントを自由に作成できます。

public class AnEvent
{
  public delegate MyReturnType MyDelegateName();
  public event MyDelegateName MyEvent;

  public void DoStuff()
  {
    MyReturnType result = null;
    if (MyEvent != null)
      result = MyEvent();
    Console.WriteLine("the event was fired");
    if (result != null)
      Console.Writeline("the result is" + result.ToString());
  }
}

public class EventListener
{
  public EventListener()
  {
    var anEvent = new AnEvent();
    anEvent.MyEvent += SomeMethod;
  }

  public MyReturnType SomeMethod()
  {
    Console.Writeline("the event was handled!");
    return new MyReturnType;
  }
}
3
Derick Bailey

戻り値の型は、関数ではなくサブルーチンであるため無効です。あなたは値を返すことができますが、イベントハンドラー(ボタンクリックイベントにフックされたサブルーチン)は正確には意図されていません。

VBでは、このコード行は次のようになります。

Private Sub button_Click(ByVal sender As Object, ByVal e As EventArgs)

この場合、VBの明示的な "Sub"ステートメントはもう少し意味がありますが、C#のすべてのvoidsは単なるサブルーチンです...コードで何かを実行することを忘れないでください引数に基づいていますが、値を返しません。ただし、change渡された引数の値は可能です。

1
EAMann

私の大学教授として、「それは実装に依存します」というほとんどすべての質問について言っていました。この特定のケースでは、イベントハンドラーを使用して、このパターンを実装して呼び出し元のコードに何かを返すことを妨げる暗黙的なものは何もありません。ただし、送信者オブジェクトと元のイベント引数の両方が渡され、基本的に実行環境コンテキストが形成されます。これらの参照を直接操作して関連する機能を実現できるため、何も返す必要はありません。

他のフレームワークでは、イベントハンドラーが何かを返すことができる場合があります。

0
Jose Diaz