Antworten:
Wenn Sie eine Delegateninstanz haben, kennen Sie möglicherweise den genauen Typ oder wissen nur, dass es sich um eine handelt Delegate
. Wenn Sie den genauen Typ kennen, können Sie ihn verwenden Invoke
, was sehr schnell geht - alles ist bereits vorab validiert. Beispielsweise:
Func<int,int> twice = x => x * 2;
int i = 3;
int j = twice.Invoke(i);
// or just:
int j = twice(i);
Jedoch! Wenn Sie nur wissen, dass Delegate
dies der Fall ist, müssen die Parameter usw. manuell aufgelöst werden - dies kann das Auspacken usw. beinhalten - es wird viel nachgedacht. Beispielsweise:
Delegate slowTwice = twice; // this is still the same delegate instance
object[] args = { i };
object result = slowTwice.DynamicInvoke(args);
Hinweis: Ich habe die args
lange Hand geschrieben, um zu verdeutlichen, dass es sich um eine object[]
handelt. Hier fallen viele zusätzliche Kosten an:
MethodInfo
Vermeiden DynamicInvoke
Sie grundsätzlich, wann immer Sie können. Invoke
ist immer vorzuziehen, es sei denn, Sie haben nur ein Delegate
und einobject[]
.
Für einen Leistungsvergleich wird im Release-Modus außerhalb des Debuggers (einer Konsolen-Exe) Folgendes gedruckt:
Invoke: 19ms
DynamicInvoke: 3813ms
Code:
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
. Warum vergleichen Sie sie mehr als 1 Anruf? Und warum dauert der erste länger als der zweite Funktionsaufruf?