Invoke ve DynamicInvoke Arasındaki Fark


128

Temsilcilerdeki Invoke ve DynamicInvoke arasındaki fark nedir? Lütfen bana bu iki yöntem arasındaki farkı açıklayan bir kod örneği verin.

Yanıtlar:


206

Temsilci bir örneğiniz olduğunda, türü tam olarak biliyor olabilirsiniz veya yalnızca bir Delegate. Tam türü biliyorsanız, kullanabilirsiniz Invoke, ki bu çok hızlıdır - her şey zaten önceden doğrulanmıştır. Örneğin:

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

Ancak! Sadece bunun olduğunu biliyorsanız Delegate, parametreleri vb. Manuel olarak çözmesi gerekir - bu kutudan çıkarmayı içerebilir, vb - çok fazla yansıma oluyor. Örneğin:

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

Not argsUzun eli object[], an'ın dahil olduğunu açıkça belirtmek için yazdım . Burada çok fazla ekstra maliyet var:

  • dizi
  • aktarılan bağımsız değişkenlerin doğrulanması gerçek için "uygun" MethodInfo
  • gerektiğinde kutudan çıkarma vb.
  • yansıma-çağırmak
  • daha sonra arayanın dönüş değerini işlemek için bir şeyler yapması gerekir

Temel olarak, DynamicInvokeelinizden geldiğince kaçının . Invokesahip olduğunuz tek şey a Delegateve bir olmadığı sürece her zaman tercih edilir object[].

Performans karşılaştırması için, hata ayıklayıcının (bir konsol exe) dışında yayın modunda aşağıdakiler yazdırılır:

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);

3
Bu, kullanım durumunda DynamicInvoke derleyicisinin temsilci çağrısını işlemek için daha fazla IL kodu ürettiği anlamına mı geliyor?
testCoder

2
@testCoder hayır, yansıma kullanacak
Marc Gravell

@MarcGravell bunu olay yaratan bir yöntemde denediğimde ilk yöntem çağrısı alıyorum yaklaşık 0,7766 ms sürüyor ancak ikincisi 0,0568 ms civarında sürüyor. Birincisi Invoke olduğunda, DynamicInvoke'tan daha uzun sürer veya tam tersi. Örneğinizi 1 döngü ile denediğimde ve ms'ye bakın Invoke: 0,0478ms, DynamicInvoke: 0,053ms. Neden onları 1'den fazla aramayla karşılaştırıyorsunuz? Ve neden birincisi ikinci işlev çağrısından daha uzun sürüyor?
uzay95

4
@ uzay95 Yönteme yapılan ilk çağrı, JIT derlemesinin CLR tarafından gerçekleştirilmesine neden olur - bu, işlem başladıktan sonra ilk çağrıldığında herhangi bir yöntem için geçerlidir. Bu tür bir senaryoda, üç şeyden birini yapabilirsiniz: (1) yöntemi birkaç kez çalıştırın, böylece ilk arama için geçen süre nihai sonuçta önemsiz hale gelir, (2) sizden sonrasına kadar ölçmeye başlamayın yöntemi bir kez çağırdım veya (3) ngen.exe'yi (aşırı öldürme) kullanın. Bu gönderi yeterince açıklıyor ... stackoverflow.com/questions/4446203/…
Quanta

@ marc-gravell Yöntem imzası , args parametresi için params anahtar sözcüğünü belirttiğinden, DynamicInvoke'a geçmek için bir dizi oluşturmanıza gerek yoktur .
zodo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.