Jaka jest różnica między Invoke i DynamicInvoke w delegatach? Proszę podać przykład kodu, który wyjaśnia różnicę między tymi dwiema metodami.
Odpowiedzi:
Gdy masz wystąpienie delegata, możesz znać dokładny typ lub po prostu wiedzieć, że jest to Delegate
. Jeśli znasz dokładny typ, możesz użyć Invoke
, co jest bardzo szybkie - wszystko jest już wstępnie sprawdzone. Na przykład:
Func<int,int> twice = x => x * 2;
int i = 3;
int j = twice.Invoke(i);
// or just:
int j = twice(i);
Jednak! Jeśli po prostu wiesz, że tak jest Delegate
, musi rozwiązać parametry itp. Ręcznie - może to wymagać rozpakowania itp. - dzieje się wiele refleksji. Na przykład:
Delegate slowTwice = twice; // this is still the same delegate instance
object[] args = { i };
object result = slowTwice.DynamicInvoke(args);
Uwaga: Napisałem args
długą rękę, aby wyjaśnić, że w object[]
grę wchodzi. Istnieje wiele dodatkowych kosztów:
MethodInfo
Zasadniczo unikaj, DynamicInvoke
kiedy tylko możesz. Invoke
jest zawsze preferowane, chyba że wszystko, co masz, to a Delegate
i object[]
.
W celu porównania wydajności drukuje w trybie wydania poza debuggerem (exe konsoli):
Invoke: 19ms
DynamicInvoke: 3813ms
Kod:
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
. Dlaczego porównujesz je z więcej niż jednym połączeniem? I dlaczego pierwsze trwa dłużej niż drugie wywołanie funkcji?