使用DynamicInvoke直接调用委托和使用DynamicInvokeImpl有什么区别?

时间:2009-05-31 19:40:09

标签: c# delegates

DynamicInvoke和DynamicInvokeImpl的文档都说:

  

动态调用(后期绑定)   当前所代表的方法   委派。

我注意到DynamicInvoke和DynamicInvokeImpl采用了一个对象数组而不是一个特定的参数列表(这是我猜的后期部分)。但这是唯一的区别吗? DynamicInvoke和DynamicInvokeImpl之间有什么区别。

3 个答案:

答案 0 :(得分:33)

直接调用它(Invoke(...)的简称)和使用DynamicInvoke之间的主要区别在于性能;根据我的衡量标准(下图)超过* 700的因素。

使用直接/ Invoke方法,参数已经通过方法签名预先验证,并且代码已经存在以直接将这些参数传递给方法(我会说“作为IL”,但我似乎回想一下,运行时直接提供了这个,没有任何IL)。对于DynamicInvoke,它需要通过反射从数组中检查它们(即它们是否都适用于此调用;它们是否需要拆箱等);这是(如果您在紧密循环中使用它),应尽可能避免使用。

实施例;结果首先(我增加了前一次编辑的LOOP计数,以进行合理的比较):

Direct: 53ms
Invoke: 53ms
DynamicInvoke (re-use args): 37728ms
DynamicInvoke (per-cal args): 39911ms

使用代码:

static void DoesNothing(int a, string b, float? c) { }
static void Main() {
    Action<int, string, float?> method = DoesNothing;

    int a = 23;
    string b = "abc";
    float? c = null;
    const int LOOP = 5000000;

    Stopwatch watch = Stopwatch.StartNew();
    for (int i = 0; i < LOOP; i++) {
        method(a, b, c);
    }
    watch.Stop();
    Console.WriteLine("Direct: " + watch.ElapsedMilliseconds + "ms");

    watch = Stopwatch.StartNew();
    for (int i = 0; i < LOOP; i++) {
        method.Invoke(a, b, c);
    }
    watch.Stop();
    Console.WriteLine("Invoke: " + watch.ElapsedMilliseconds + "ms");

    object[] args = new object[] { a, b, c };
    watch = Stopwatch.StartNew();
    for (int i = 0; i < LOOP; i++) {
        method.DynamicInvoke(args);
    }
    watch.Stop();
    Console.WriteLine("DynamicInvoke (re-use args): "
         + watch.ElapsedMilliseconds + "ms");

    watch = Stopwatch.StartNew();
    for (int i = 0; i < LOOP; i++) {
        method.DynamicInvoke(a,b,c);
    }
    watch.Stop();
    Console.WriteLine("DynamicInvoke (per-cal args): "
         + watch.ElapsedMilliseconds + "ms");
}

答案 1 :(得分:10)

巧合的是,我发现了另一个不同之处。

如果Invoke抛出异常,则可以通过预期的异常类型捕获它。 但是DynamicInvoke会引发TargetInvokationException。这是一个小型演示:

using System;
using System.Collections.Generic;

namespace DynamicInvokeVsInvoke
{
   public class StrategiesProvider
   {
      private readonly Dictionary<StrategyTypes, Action> strategies;

      public StrategiesProvider()
      {
         strategies = new Dictionary<StrategyTypes, Action>
                      {
                         {StrategyTypes.NoWay, () => { throw new NotSupportedException(); }}
                         // more strategies...
                      };
      }

      public void CallStrategyWithDynamicInvoke(StrategyTypes strategyType)
      {
         strategies[strategyType].DynamicInvoke();
      }

      public void CallStrategyWithInvoke(StrategyTypes strategyType)
      {
         strategies[strategyType].Invoke();
      }
   }

   public enum StrategyTypes
   {
      NoWay = 0,
      ThisWay,
      ThatWay
   }
}

当第二个测试变为绿色时,第一个测试面临TargetInvokationException。

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SharpTestsEx;

namespace DynamicInvokeVsInvoke.Tests
{
   [TestClass]
   public class DynamicInvokeVsInvokeTests
   {
      [TestMethod]
      public void Call_strategy_with_dynamic_invoke_can_be_catched()
      {
         bool catched = false;
         try
         {
            new StrategiesProvider().CallStrategyWithDynamicInvoke(StrategyTypes.NoWay);
         }
         catch(NotSupportedException exc)
         {
            /* Fails because the NotSupportedException is wrapped
             * inside a TargetInvokationException! */
            catched = true;
         }
         catched.Should().Be(true);
      }

      [TestMethod]
      public void Call_strategy_with_invoke_can_be_catched()
      {
         bool catched = false;
         try
         {
            new StrategiesProvider().CallStrategyWithInvoke(StrategyTypes.NoWay);
         }
         catch(NotSupportedException exc)
         {
            catched = true;
         }
         catched.Should().Be(true);
      }
   }
}

答案 2 :(得分:9)

两者之间确实没有功能差异。如果你在反射器中提取实现,你会注意到DynamicInvoke只是使用相同的参数集调用DynamicInvokeImpl。没有进行额外的验证,它是一个非虚方法,所以它的行为不可能被派生类改变。 DynamicInvokeImpl是一个虚拟方法,可以完成所有实际工作。