2012-05-30 15 views
21

Yansımayı kullanmayla ilgili performans sorunları yaşıyorum.
Ben de nesnelerin özellikleri için delegelerini oluşturmaya karar ve şimdiye kadar bu var: Sonuçlar yaklaşık 30-40 kat daha hızlı geleneksel yöntem kullanılarak daha yüksek ölçüde tatmin edildiYansıma Performansı - Yetki Oluşturun (Özellikler C#)

TestClass cwp = new TestClass(); 
var propertyInt = typeof(TestClass).GetProperties().Single(obj => obj.Name == "AnyValue"); 
var access = BuildGetAccessor(propertyInt.GetGetMethod()); 
var result = access(cwp); 
static Func<object, object> BuildGetAccessor(MethodInfo method) 
{ 
    var obj = Expression.Parameter(typeof(object), "o"); 

    Expression<Func<object, object>> expr = 
     Expression.Lambda<Func<object, object>>(
      Expression.Convert(
       Expression.Call(
        Expression.Convert(obj, method.DeclaringType), 
        method), 
       typeof(object)), 
      obj); 

    return expr.Compile(); 
} 

(PropertyInfo.GetValue (obj, null);)

Sorun şu: Aynı şekilde çalışan bir SetValue özelliğini nasıl yapabilirim? Ne yazık ki bir yol almadı.

Uygulamamın yapısı nedeniyle <T> ile yöntemleri kullanamadığım için yapıyorum.

+0

"Birlikte yöntemleri kullanamaz çünkü böylece yapıyorum" - Bu senin NETFX sürümünü <2.0 anlamına mı geliyor? Neden uygulamanızda jenerik kullanmıyorsunuz? –

+0

Ayrıca, mülkler için delege oluşturarak gelmez Ne yansıması ile ne ilgisi var ve ne sorun yansıma kullanarak çözmeye çalışıyorsunuz? –

+0

Delegeler çok daha iyi performansa sahiptir ve dinamik olarak kullanılabilir. Dinamik çağrıyı kullanmanız gerektiğinde tercih edilen seçeneklerdir. – GregRos

cevap

15

Bu sizin için çalışması gerekir:

static Action<object, object> BuildSetAccessor(MethodInfo method) 
{ 
    var obj = Expression.Parameter(typeof(object), "o"); 
    var value = Expression.Parameter(typeof(object)); 

    Expression<Action<object, object>> expr = 
     Expression.Lambda<Action<object, object>>(
      Expression.Call(
       Expression.Convert(obj, method.DeclaringType), 
       method, 
       Expression.Convert(value, method.GetParameters()[0].ParameterType)), 
      obj, 
      value); 

    return expr.Compile(); 
} 

Kullanımı:

var accessor = BuildSetAccessor(typeof(TestClass).GetProperty("MyProperty").GetSetMethod()); 
var instance = new TestClass(); 
accessor(instance, "foo"); 
Console.WriteLine(instance.MyProperty); 

TestClass olarak:

public class TestClass 
{ 
    public string MyProperty { get; set; } 
} 

Baskılar dışarı:

foo

2

Dinamik türleri kullanın. Kaputun altındaki yansımayı kullanıyorlar, ancak çok daha hızlı.

Aksi

...

izin verici lisanslarla orada ücretsiz hızlı yansıma kütüphanelerinin ton vardır. Seni bağlarım, ama çok fazla var, ve sana hangisinin uygun olduğuna emin değilim. Sadece codeplex'i arayın. Beğendiğiniz bir şey bulduğunuzda, onu deneyin.

Ama evet, belki ondan önce, düşüncenin gerçekten cevabının cevabı olduğunu düşün. Çoğu zaman başka çözümler de vardır.

Düzenleme: İstenen olarak ...

http://geekswithblogs.net/SunnyCoder/archive/2009/06/26/c-4.0-dynamics-vs.-reflection.aspx
http://theburningmonk.com/2010/09/performance-test-dynamic-method-invocation-in-csharp-4/
http://www.mssoftwareconsulting.com/msswc/blog/post/C-40-and-dynamic-performance.aspx

Bilindiği kadarıyla söyleyebilirim bu.

+0

Üzgünüm? Neden olumsuz oy kullanmalı? – GregRos

+1

Dynamics ** başka bir yol olmadıkça, yansıma IMO için kullanılmamalıdır **. Destekleyen bazı verileri yükleyebilir misiniz * çok daha hızlıdır *? ... ve OP'nin istediği şekilde dinamik kullanmanın bir örneği? Bunlar olumsuz oyların sebeplerinden bazıları olabilir ... – IAbstract

+0

Dinamik çağrıyı kullanıyor. Örneğin. yöntemleri, özellikleri vb. ayarlama. Bu ** tam olarak ** dinamiklerle ne yapacağınız. – GregRos

10

Performans önemliyse, CreateDelegate yapısından daha iyi olacağınızı düşünüyorum. Önceden yöntemin imzasını bildiğinizden, burada PropertyInfo'un sadece GetGetMethod ve GetSetMethod olduğu gibi, doğrudan aynı imzayla çok yöntemi yürütmek için bir temsilci oluşturabilirsiniz. Temsilciler için bazı mantık (bir yöntem tanıtıcısı yoktu) oluşturmanız gerekiyorsa ifadeler daha uygun olacaktır.Ben bu soruna farklı yolları üzerinde bazı kıyaslama yaptı: yaklaşık 10000000 aramalar için

Func<S, T> Getter; 
Action<S, T> Setter; 
PropertyInfo Property; 
public void Initialize(Expression<Func<S, T>> propertySelector) 
{ 
    var body = propertySelector.Body as MemberExpression; 
    if (body == null) 
     throw new MissingMemberException("something went wrong"); 

    Property = body.Member as PropertyInfo; 



    //approaches: 

    //Getter = s => (T)Property.GetValue(s, null); 

    //Getter = memberSelector.Compile(); 

    //ParameterExpression inst = Expression.Parameter(typeof(S)); 
    //Getter = Expression.Lambda<Func<S, T>>(Expression.Property(inst, Property), inst).Compile(); 

    //var inst = Expression.Parameter(typeof(S)); 
    //Getter = Expression.Lambda<Func<S, T>>(Expression.Call(inst, Property.GetGetMethod()), inst).Compile(); 

    //Getter = (Func<S, T>)Delegate.CreateDelegate(typeof(Func<S, T>), Property.GetGetMethod()); 



    //Setter = (s, t) => Property.SetValue(s, t, null); 

    //var val = Expression.Parameter(typeof(T)); 
    //var inst = Expression.Parameter(typeof(S)); 
    //Setter = Expression.Lambda<Action<S, T>>(Expression.Call(inst, Property.GetSetMethod(), val), 
    //           inst, val).Compile(); 

    //Setter = (Action<S, T>)Delegate.CreateDelegate(typeof(Action<S, T>), Property.GetSetMethod()); 
} 


//Actual calls (tested under loop): 
public T Get(S instance) 
{ 
    //direct invocation: 
    //return (T)Property.GetValue(instance, null); 

    //calling the delegate: 
    //return Getter(instance); 
} 
public void Set(S instance, T value) 
{ 
    //direct invocation: 
    //Property.SetValue(instance, value, null); 

    //calling the delegate: 
    //Setter(instance, value); 
} 

Sonuçları - (Get Set):

GetValue-SetValue (direkt): 3800 ms, 5500 ms

GetValue-SetValue (temsilci): 3600 ms, 5300 ms

derlenmiş ifadeler:

Get: Expression.Property: 280 ms 

     Expression.Call: 280 ms 

     direct compile: 280 ms 
    Set: 300 ms 

temsilci oluşturun: 130 ms, 135 ms

doğrudan mülkiyet çağrı: 70 ms, 70 ms

Ben senin olayda, yazardı:

public static Func<S, T> BuildGetAccessor<S, T>(Expression<Func<S, T>> propertySelector) 
{ 
    return propertySelector.GetPropertyInfo().GetGetMethod().CreateDelegate<Func<S, T>>(); 
} 

public static Action<S, T> BuildSetAccessor<S, T>(Expression<Func<S, T>> propertySelector) 
{ 
    return propertySelector.GetPropertyInfo().GetSetMethod().CreateDelegate<Action<S, T>>(); 
} 

// a generic extension for CreateDelegate 
public static T CreateDelegate<T>(this MethodInfo method) where T : class 
{ 
    return Delegate.CreateDelegate(typeof(T), method) as T; 
} 

public static PropertyInfo GetPropertyInfo<S, T>(this Expression<Func<S, T>> propertySelector) 
{ 
    var body = propertySelector.Body as MemberExpression; 
    if (body == null) 
     throw new MissingMemberException("something went wrong"); 

    return body.Member as PropertyInfo; 
} 

Yani şimdi diyorsunuz:

TestClass cwp = new TestClass(); 
var access = BuildGetAccessor((TestClass t) => t.AnyValue); 
var result = access(cwp); 

Bu simpl değil mi? er ?? Tam olarak işlemek için genel bir sınıf here yazmıştı. "Çünkü benim uygulamasının yapısının" < T >