【问题标题】:MethodInvoker vs Action for Control.BeginInvokeControl.BeginInvoke 的 MethodInvoker 与 Action
【发布时间】:2010-11-13 03:47:20
【问题描述】:

哪个更正确,为什么?

Control.BeginInvoke(new Action(DoSomething), null);

private void DoSomething()
{
    MessageBox.Show("What a great post");
}

Control.BeginInvoke((MethodInvoker) delegate { 
    MessageBox.Show("What a great post");
}); 

我觉得我在做同样的事情,那么什么时候使用 MethodInvokerAction,甚至编写 lambda 表达式是合适的时间?

编辑:我知道编写 lambda 与 Action 之间并没有太大区别,但 MethodInvoker 似乎是为特定目的而制作的。它有什么不同吗?

【问题讨论】:

标签: c# .net delegates invoke


【解决方案1】:

不要忘记以某种方式检查当前是否有可用的控件,以避免在关闭表单时出错。

if(control.IsHandleCreated)
control.BeginInvoke((MethodInvoker)(() => control.Text="check123"));

【讨论】:

    【解决方案2】:

    对于下面的每个解决方案,我运行 131072 (128*1024) 次迭代(在一个单独的线程中)。 VS2010 性能助手给出了这样的结果:

    • 只读 MethodInvoker:5664.53 (+0%)
    • 新 MethodInvoker:5828.31 (+2.89%)
    • MethodInvoker 中的函数转换:5857.07 (+3.40%)
    • 只读操作:6467.33 (+14.17%)
    • 新动作:6829.07 (+20.56%)

    在每次迭代中调用新的操作

        private void SetVisibleByNewAction()
        {
            if (InvokeRequired)
            {
                Invoke(new Action(SetVisibleByNewAction));
            }
            else
            {
                Visible = true;
            }
        }
    

    在每次迭代时调用只读、内置构造函数、Action

        // private readonly Action _actionSetVisibleByAction
        // _actionSetVisibleByAction= SetVisibleByAction;
        private void SetVisibleByAction()
        {
            if (InvokeRequired)
            {
                Invoke(_actionSetVisibleByAction);
            }
            else
            {
                Visible = true;
            }
        }
    

    在每次迭代时调用一个新的 MethodInvoker

        private void SetVisibleByNewMethodInvoker()
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(SetVisibleByNewMethodInvoker));
            }
            else
            {
                Visible = true;
            }
        }
    

    在每次迭代时调用只读的内置构造函数 MethodInvoker

        // private readonly MethodInvoker _methodInvokerSetVisibleByMethodInvoker 
        // _methodInvokerSetVisibleByMethodInvoker = SetVisibleByMethodInvoker;
        private void SetVisibleByMethodInvoker()
        {
            if (InvokeRequired)
            {
                Invoke(_methodInvokerSetVisibleByMethodInvoker);
            }
            else
            {
                Visible = true;
            }
        }
    

    在每次迭代时调用 MethodInvoker 中的函数转换

        private void SetVisibleByDelegate()
        {
            if (InvokeRequired)
            {
                Invoke((MethodInvoker) SetVisibleByDelegate);
            }
            else
            {
                Visible = true;
            }
        }
    

    “新行动”解决方案的调用示例:

        private void ButtonNewActionOnClick(object sender, EventArgs e)
        {
            new Thread(TestNewAction).Start();
        }
    
        private void TestNewAction()
        {
            var watch = Stopwatch.StartNew();
            for (var i = 0; i < COUNT; i++)
            {
                SetVisibleByNewAction();
            }
            watch.Stop();
            Append("New Action: " + watch.ElapsedMilliseconds + "ms");
        }
    

    【讨论】:

    • 您如何阅读此结果?我是分析新手。一个链接会很有帮助。
    【解决方案3】:

    也根据 MSDN:

    MethodInvoker 提供了一个简单的委托,用于调用带有 void 参数列表的方法。当调用控件的 Invoke 方法时,或者当您需要一个简单的委托但不想自己定义一个委托时,可以使用此委托。

    另一方面,一个动作最多可以采用 4 个参数。

    但我认为 MethodInvokerAction 之间没有任何区别,因为它们都只是封装了一个不带参数并返回 的委托无效

    如果您查看它们的定义,您就会明白这一点。

    public delegate void MethodInvoker();
    public delegate void Action();
    

    顺便说一句,你也可以把你的第二行写成。

    Control.BeginInvoke(new MethodInvoker(DoSomething), null);
    

    【讨论】:

    • 您甚至可以将其重写为: Control.BeginInvoke(new MethodInvoker(DoSomething));或 Control.BeginInvoke(new MethodInvoker(() => { DoSomething(); }));
    • 根据文档,Action 最多可以使用 16 个参数。 docs.microsoft.com/en-us/dotnet/api/…
    【解决方案4】:

    我更喜欢使用 lambdas 和 Actions/Funcs:

    Control.BeginInvoke(new Action(() => MessageBox.Show("What a great post")));
    

    【讨论】:

      【解决方案5】:

      两者同样正确,但Control.Invoke 的文档指出:

      委托可以是 EventHandler,在这种情况下是发送者 参数将包含此控件, 并且事件参数将包含 EventArgs.Empty。委托人也可以 是 MethodInvoker 的一个实例,或者 任何其他无效的代表 参数列表。一个电话 EventHandler 或 MethodInvoker 委托 会比打电话给另一个人更快 代表的类型。

      所以MethodInvoker 会是更有效的选择。

      【讨论】:

      • 感谢 Jon,但是是什么让 MethodInvoker 比不带参数的 Action 调用更高效?
      • 简单地说:听起来它使用 is/as 检查(作为特殊情况)检查这两个,并使用 Invoke,而不是 DynamicInvoke - 明显更快
      【解决方案6】:

      Action 是在 System 中定义的,而 MethodInvoker 是在 System.Windows.Forms 中定义的——你最好使用 Action,因为它可以移植到其他地方。您还会发现接受 Action 作为参数的地方比 MethodInvoker 更多。

      但是,文档确实表明在 Control.Invoke() 中调用 EventHandler 或 MethodInvoker 类型的委托将比任何其他类型更快。

      除了它们所在的命名空间之外,我不认为 Action 和 MethodInvoker 之间存在有意义的功能差异 - 它们基本上都被定义为:

      public delegate void NoParamMethod();
      

      顺便说一句,Action 有几个重载允许传入参数 - 它是通用的,因此它们可以是类型安全的。

      【讨论】:

        【解决方案7】:

        在大多数情况下这是一个偏好问题,除非您打算重用 DoSomething() 方法。此外,匿名函数会将您的作用域变量放在堆上,可能会使其成为更昂贵的函数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-05-08
          • 2011-06-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多