web-dev-qa-db-ja.com

EventHandlerを介して戻り値を渡す

APIに書き込もうとしていますが、テーブルからデータを取得するときにイベントハンドラを呼び出す必要があります。このようなもの:

    public override bool Run(Company.API api)
    {
        SomeInfo _someInfo = new SomeInfo();

        if (_someInfo.Results == 1)
            return true;
        else
            return false;

        using (MyTable table = new MyTable(api))
        {
            table.WhenData += new EventHandler<DataEventArgs<Record>>(table_WhenData);
            table.WhenDead += new EventHandler<EventArgs>(table_WhenDead);
            table.Start();
        }

    public void table_WhenData(object sender, DataEventArgs<Record> e)
    {
        return true;
    }

Imが抱えている問題は、table_WhenDataからRunメソッドに戻り値を渡す方法がわからないことです。

(_someInfoをメソッドに渡そうとするなど)多くの方法を試しましたが、構文が正しくないようです。

どんな提案も大歓迎です。

34
Leroy Jenkins

ここでの一般的なパターンは、イベントハンドラーからデータを返すのではなく、イベント引数オブジェクトにプロパティを追加して、イベントのコンシューマーが呼び出し元がアクセスできるプロパティを設定できるようにすることです。これは、UI処理コードで非常に一般的です。いたるところにイベントのキャンセルコンセプトが表示されます。

以下は疑似コードであり、コンパイルの準備ができていません。その意図はパターンを示すことです。

public class MyEventArgs : EventArgs
{
   public bool Cancel{get;set;}
}

public bool fireEvent()
{
    MyEventArgs e=new MyEventArgs();

    //Don't forget a null check, assume this is an event
    FireEventHandler(this,e);

    return e.Cancel;
}

public HandleFireEvent(object sender, MyEventArgs e)
{
 e.Cancel=true;
}

編集

Jon Skeetの言い方が気に入っています。EventArgsを変更可能にします。つまり、イベントのコンシューマーはEventArgsオブジェクトの状態を変更して、イベントの発生者がそのデータにアクセスできるようにすることができます。

50
JoshBerke

私はこれが古い投稿であることを知っていますが、誰かがそれに遭遇した場合に備えて、確かにこれを行うことが可能です。値を返す独自のデリゲートを宣言し、この新しいデリゲートに基づいてイベントを作成します。次に例を示します。

イベント宣言者/発行者:

// the delegate
public delegate string ReturnStringEventHandler(object sender, EventArgs args);
// the event
public event ReturnStringEventHandler StringReturnEvent;
// raise the event
protected void OnStringReturnEvent(EventArgs e)
    {
        if (StringReturnEvent != null)  // make sure at least one subscriber
              // note the event is returning a string
              string myString = StringReturnEvent(this, e);
    }

イベントのサブスクライバー:

// Subscribe to event, probably in class constructor / initializer method
StringReturnEvent += HandleStringReturnEvent;

// Handle event, return data
private string HandleStringReturnEvent(object sender, EventArgs e)
{
    return "a string to return";
}

.NETは、この例をAssemblyResolveイベントで提供します。このイベントでは、ResolveEventHandlerデリゲートを使用してデータ(この場合は目的のアセンブリへの参照)を返します。 AssemblyResolveイベントに関するMSDN記事

私は個人的にAssemblyResolveイベントとカスタムデリゲート手法の両方を使用してイベントからデータを返しましたが、どちらもVisual Studio 2010で期待どおりに機能します。

28
AFischbein

これを行う唯一の方法は、引数の1つ(できれば「送信者」ではなく「引数」)を変更可能にすることです。まだ変更可能でない場合は、基本的に問題が発生しています。情報を取得する方法はありません。

(さて、1つの方法があります-イベント引数自体を不変に保つことができますが、その1つのメンバーを、最初にイベントを発生させるコードによって登録されたデリゲートを呼び出すことになるメソッドにします。しかし、それは恐ろしいことです...)

19
Jon Skeet

簡単な解決策はクロージャーを使うことです:

public override bool Run() {
    SomeInfo someInfo = ...
    table.WhenData += (obj, args) => {
        someInfo.Return = something
    };
}
1
Igor ostrovsky