Подтвердить что ты не робот

Разница между Invoke и DynamicInvoke

В чем разница между Invoke и DynamicInvoke в делегатах? Пожалуйста, дайте мне пример кода, который объясняет разницу между этими двумя методами.

4b9b3361

Ответ 1

Когда у вас есть экземпляр делегата, вы можете узнать точный тип, или вы можете просто знать, что это Delegate. Если вы знаете точный тип, вы можете использовать Invoke, который очень быстро - все уже предварительно проверено. Например:

Func<int,int> twice = x => x * 2;
int i = 3;
int j = twice.Invoke(i);
// or just:
int j = twice(i);

Однако! Если вы просто знаете, что это Delegate, он должен вручную разрешить параметры и т.д. - это может включать распаковку и т.д. - происходит много размышлений. Например:

Delegate slowTwice = twice; // this is still the same delegate instance
object[] args = { i };
object result = slowTwice.DynamicInvoke(args);

Примечание. Я написал длинную руку args, чтобы было ясно, что задействован object[]. Здесь много дополнительных затрат:

  • массив
  • Проверка прошедших аргументов является "подходящей" для фактического MethodInfo
  • распаковка и т.д. по мере необходимости
  • отражательного Invoke
  • то вызывающему нужно что-то сделать для обработки возвращаемого значения

В принципе, избегайте DynamicInvoke, когда это возможно. Invoke всегда предпочтительнее, если только у вас нет Delegate и object[].

Для сравнения производительности следующее в режиме освобождения вне отладчика (консоль exe) печатает:

Invoke: 19ms
DynamicInvoke: 3813ms

код:

Func<int,int> twice = x => x * 2;
const int LOOP = 5000000; // 5M
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
    twice.Invoke(3);
}
watch.Stop();
Console.WriteLine("Invoke: {0}ms", watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
    twice.DynamicInvoke(3);
}
watch.Stop();
Console.WriteLine("DynamicInvoke: {0}ms", watch.ElapsedMilliseconds);