1

イベント デリゲートのサブスクライバー リストを反復処理するために必要なコードを静的ヘルパー ルーチンにラップしようとしています。これにより、多くのイベント ハンドラーに対して同じコードをコピーして貼り付ける必要がなくなります。私はまだ C# の詳細を学んでおり、詳細につまずいています。

ヘルパー ルーチンは、イベント サブスクライバー リストを反復処理し、各サブスクライバーを個別に呼び出して、サブスクライバーのスレッドを自動的に同期できるようにします。イベントの多くは、GUI のさまざまなフォームからサブスクライブされるため、各フォーム クラスでイベントのスレッド同期を管理する必要がなくなります。

以下のコードは、概念の例を示しています。最後の行....

singleCast.Invoke(paramList);

...明らかに、いくつかの理由で有効ではありません。

非常に遅いことがわかっている DynamicInvoke メソッドを使用せずに、各サブスクライバーを呼び出すにはどうすればよいですか?

ForEach が特定のイベント Delegates とジェネリック Delegates を返すように型参照を渡す方法はありますか?

以下のコード例を参照してください。

namespace Reflection_Diagnostics
{
    // ***********************
    // *** Event Delegates ***
    // ***********************

    public delegate void SystemPoll();
    public delegate void SystemStart(int option);
    public delegate void SystemEnd();

    class clsTestEvents
    {
        // **************
        // *** Events ***
        // **************

        public event SystemPoll Event_SystemPoll;
        public event SystemStart Event_SystemStart;
        public event SystemEnd Event_SystemEnd;

        // ***********************
        // *** Event Overrides ***
        // ***********************

        private void OnEvent_SystemPoll()  // Event Override
        {
            MyToolBox.SyncEvents(Event_SystemPoll);
        }

        private void OnEvent_SystemStart(int option)  // Event Override
        {
            MyToolBox.SyncEvents(Event_SystemStart, option);
        }

        private void OnEvent_SystemEnd()  // Event Override
        {
            MyToolBox.SyncEvents(Event_SystemEnd);
        }

        // ***********************
        // *** Test The Events ***
        // ***********************

        public void TestTheEvents()
        {
            Event_SystemPoll();
            Event_SystemStart(1);
            Event_SystemEnd();
        }
    }

    public class MyToolBox
    {
        // *******************
        // *** Sync Events ***
        // *******************
        // Iterate through the event subscriber list and synchronize to the subscriber thread when needed

        static public void SyncEvents(Delegate handler,  params object[] paramList)
        {
            if (null != handler)
            {
                foreach (Delegate singleCast in handler.GetInvocationList())
                {
                    ISynchronizeInvoke syncInvoke = singleCast.Target as ISynchronizeInvoke;
                    try
                    {
                        if ((syncInvoke != null) && (syncInvoke.InvokeRequired))
                        {
                            syncInvoke.Invoke(singleCast, paramList);   // Subscriber is on a different thread
                        }
                        else
                        {
                            // Error:  System.Delegate does not contain a definition for 'Invoke'.....
                            // singleCast is a generic Delegate, and so cannot be directly invoked.
                            // DynamicInvoke is avialable, but is much, MUCH, MUCH!! slower to execute

                            singleCast.Invoke(paramList);  // Subscriber is on the same thread
                        } 
                    }
                    catch
                    {
                    }
                }
            }
        }
    }
}
4

1 に答える 1

0

あなたが何を求めているのかは明確ではありません。メソッドを使用する必要はありませんDynamicInvoke。デリゲートを「呼び出す」だけです。

foreach (EventHandler<EventArgs> subscriber in handler.GetInvocationList())
{
    ISynchronizeInvoke control = null;
    if (subscriber.Target != null)
    {
        control = subscriber.Target as ISynchronizeInvoke;
    }
    if (control != null)
    {
        if (control.InvokeRequired)
        {
            control.BeginInvoke(subscriber, new object[] {this, EventArgs.Empty});
            continue;
        }
    }
    subscriber(this, EventArgs.Empty); // just "call"
}

しかし、あなたのサンプルコードはを使用していなかったDynamicInvokeので、問題が何であるかはわかりません。

Targetサンプルコードまたは上記のコードを使用しても、呼び出すインスタンス()がない場合があります。InvokeRequired次に例を示します。

    button1.Click += button1_Click;
//...

private static void button1_Click(object sender, EventArgs e)
{
    Button button = sender as Button;
    if (button == null) throw new InvalidOperationException();
    DoSomeAsyncOperation();
}

また

button1.Click += (o, args) =>
                    {
                    DoSomethingOnClick();
                    };

したがって、実際には、必要なものだけを取得することがあり、フレームワークのユーザーはそれでも時々対処する必要がありInvokeRequiredます。さらに、winformsまたはWPFの他のほとんどすべての実装とは異なるコードを作成させるため、学習が難しくなります。さらに、「非表示」の非同期呼び出しは、次のようになります。非表示-デバッグが困難になります。

于 2012-09-21T16:48:48.707 に答える