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。另外,您让他们创建的代码与 winform 或 WPF 上的几乎所有其他实现都不同,从而使其更难学习。此外,“隐藏”的异步调用就是这样:隐藏——使其更难调试。

于 2012-09-21T16:48:48.707 回答