2010-07-26 38 views
7

Doğrudan bir yöntemi çağıran bir ifade ağacı oluşturmak mümkün mü? Örneğin, aşağıdaki yöntemi göz önünde bulundurun:Bir yöntemi çağıran bir ifade ağacı oluşturma

public static int MyFunc(int a, int b) 
{ 
    return a + b; 
} 

Ben parametreleri a = 1 ve b = 2 ile MyFunc çağıran bir ifade ağaç oluşturmak istiyoruz. Bunu yapmanın bir yolu, yansıma ile; yansıma yavaş ve çalışma zamanı hataları içine derleme zamanı hataları ne olması gerektiği döner çünkü

var c1 = Expression.Constant(1); 
var c2 = Expression.Constant(2); 
var expr = Expression.Call(typeof(Program).GetMethod("MyFunc"), c1, c2); 

Ancak bu dezavantajlıdır.

yerine aşağıdaki yaklaşımı kullanabilirsiniz:

Expression<Func<int, int, int>> lambda = (a, b) => MyFunc(a, b); 
var expr = Expression.Invoke(lambda, c1, c2); 

Ama bu doğrudan aramak yerine bir lambda ifadede yöntemi sarar çünkü ne istiyorum hala değil.

iyi bir çözüm

böyle bir temsilci dayalı olabilir:

Func<int, int, int> del = Program.MyFunc; 
var expr = Expression.Invoke(del, c1, c2); 

Maalesef del bir temsilci ziyade bir ifadesidir çünkü derlemek gelmez. Delegeden bir ifade oluşturmanın herhangi bir yolu var mı? (Derleme zamanında delege hedefini bildiğimi unutmayın, bu nedenle burada açıklanan esnekliğe ihtiyacım yoktur: Expression Trees and Invoking a Delegate.)

Çağrısız bir çözüm, çağrıldıkları sürece iyi olmaz Hedef yöntemi mümkün olduğunca doğrudan.

Güncelleme: Bu da çalışır, ama yine de yansıması dayanır:

Func<int, int, int> del = Program.MyFunc; 
var expr = Expression.Call(del.Method, c1, c2); 

En azından derleme sırasında sorunlar yakalamak için daha olasıdır. Ama hala çalışma zamanı fiyatını ödüyor, değil mi?

+0

Kullanım durumu hakkında daha fazla bilgi yararlı olacaktır :) ör. Size verdiğiniz örneklerle, bir 'Func ' (… Funk ) 'den geçiyor olabilirsiniz (ve derleme zamanında hedefi biliyorsunuz), bu yüzden' İfade 'ağacı ne için gereklidir? – porges

+1

Bir ifadeyi derlemek, yansımaların tepesini cüceler. İfadeyi yaptığınızda sadece yansımayı bir kez yaptığınızdan, maliyeti göz ardı edilebilir. – Gabe

cevap

11

Lambdada .Compile numaralı telefonu aradığınız ve delege deposunu sakladığınız (ve yeniden kullandığınız) sürece, yalnızca yansıma fiyatını bir kez ödersiniz. Ancak

var c1 = Expression.Constant(1); 
var c2 = Expression.Constant(2); 
var expr = Expression.Call(typeof(Program).GetMethod("MyFunc"), c1, c2); 
Func<int> func = Expression.Lambda<Func<int>>(expr).Compile(); 
// ** now store func and re-use it ** 

, sadece yöntem kullanabileceğiniz bir çıplak temsilci almak için: tabii

var method = typeof(Program).GetMethod("MyFunc"); 
Func<int, int, int> func = (Func<int, int, int>) Delegate.CreateDelegate(
     typeof(Func<int, int, int>), method); 

, o zaman arayanın en sabitleri sağlamak zorunda kalıyor.

Başka bir seçenek DynamicMethod, ancak son delege önbelleğe aldığınız sürece, bu önemli daha hızlı olmayacaktır. Daha fazla esneklik (karmaşıklık fiyatına) sunar, ancak buradaki sorun görünmüyor.

İlgili konular