Відповіді:
Коли у вас є екземпляр делегата, ви можете знати точний тип, а можете просто знати, що це 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
В основному, уникайте DynamicInvoke
коли-небудь можете. Invoke
завжди кращий, якщо тільки у вас є Delegate
і є object[]
.
Для порівняння продуктивності виводиться наступне у режимі випуску поза відладчиком (консольне програмне забезпечення):
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);
Invoke: 0,0478ms, DynamicInvoke: 0,053ms
. Чому ви порівнюєте їх більше ніж 1 дзвінок? І чому перший займає більше часу, ніж другий виклик функції?