2012-05-30 31 views
21

Tôi gặp sự cố về hiệu suất khi sử dụng phản chiếu.
Vì vậy, tôi quyết định tạo ra các đại biểu cho các thuộc tính của các đối tượng của tôi và cho đến nay nhận điều này:Hiệu suất phản chiếu - Tạo đại biểu (Thuộc tính 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(); 
} 

Kết quả thu được rất khả quan, nhanh hơn bằng cách sử dụng phương pháp truyền thống khoảng 30-40 lần (PropertyInfo.GetValue (obj, null);)

Vấn đề là: Làm cách nào để tạo SetValue thuộc tính, hoạt động giống như vậy? Thật không may đã không nhận được một cách.

Tôi làm như vậy vì tôi không thể sử dụng phương thức với <T> do cấu trúc của đơn đăng ký của tôi.

+0

"Tôi đang làm như vậy bởi vì tôi không thể sử dụng phương pháp với" < T > "do cấu trúc của ứng dụng của tôi" - Điều đó có nghĩa là phiên bản NETFX <2.0 của bạn? Tại sao bạn không thể sử dụng Generics trong ứng dụng của bạn? –

+0

Ngoài ra, điều gì tạo ra các đại biểu cho các thuộc tính của bạn phải làm gì với sự phản chiếu, và bạn đang cố giải quyết vấn đề gì khi sử dụng sự phản chiếu? –

+0

Đại biểu có hiệu suất tốt hơn rất nhiều và có thể được sử dụng động. Chúng là tùy chọn ưa thích khi bạn cần sử dụng lời gọi động. – GregRos

Trả lời

15

này nên làm việc cho bạn:

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

Cách sử dụng:

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

Với TestClass:

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

In ra:

foo

2

Sử dụng các loại động. Chúng sử dụng sự phản chiếu dưới mui xe, nhưng chúng nhanh hơn nhiều hơn.

Nếu không ...

Có rất nhiều thư viện phản chiếu nhanh hơn miễn phí có giấy phép cho phép. Tôi sẽ liên kết bạn, nhưng có quá nhiều, và tôi không chắc chắn sẽ phù hợp với bạn. Chỉ cần tìm kiếm codeplex vv Khi bạn tìm thấy một cái gì đó bạn thích, hãy thử nó ra.

Nhưng vâng, có thể trước đó, hãy suy nghĩ xem phản ánh thực sự là câu trả lời. Thường thì có các giải pháp khác.

Edit: Theo yêu cầu ...

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

Đó là kiến ​​thức chung như xa như tôi có thể nói.

+0

Xin lỗi? Tại sao bỏ phiếu phủ định? – GregRos

+1

Động lực không nên được sử dụng để phản chiếu, IMO, trừ khi có ** không có cách nào khác **. Bạn có thể đăng một số dữ liệu hỗ trợ * chúng nhanh hơn rất nhiều * không? ... và một ví dụ về việc sử dụng động lực theo cách mà OP yêu cầu? Đây có thể là một số lý do cho các phiếu bầu tiêu cực ... – IAbstract

+0

Anh ấy đang sử dụng lời gọi động. Ví dụ. các phương thức thiết lập, các thuộc tính, vv Đó chính xác là ** những gì bạn phải làm với động lực học. – GregRos

10

Tôi nghĩ bạn nên làm tốt hơn với CreateDelegate xây dựng nếu hiệu suất là chìa khóa. Vì bạn biết chữ ký của phương thức trước, mà ở đây chỉ là GetGetMethodGetSetMethod của PropertyInfo, bạn có thể tạo đại biểu để thực thi phương thức rất trực tiếp với cùng một chữ ký. Các biểu thức sẽ phù hợp hơn nếu bạn cần xây dựng một số logic (mà bạn không có một phương thức xử lý) cho các đại biểu.Tôi đã làm một số điểm chuẩn trên các tuyến đường khác nhau cho vấn đề này:

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

Kết quả cho khoảng 10000000 cuộc gọi - (Get, Set):

GetValue-SetValue (trực tiếp): 3800 ms, 5500 ms

GetValue-SetValue (đại biểu): 3600 ms, 5300 ms

biểu thức biên soạn:

Get: Expression.Property: 280 ms 

     Expression.Call: 280 ms 

     direct compile: 280 ms 
    Set: 300 ms 

tạo đại biểu: 130 ms, 135 ms

trực tiếp cuộc gọi bất động sản: 70 ms, 70 ms

Tôi sẽ, trong trường hợp của bạn, viết:

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

Vì vậy bây giờ bạn gọi:

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

Điều đó không đơn giản er ?? Đã viết một lớp chung here để xử lý điều chính xác.

Các vấn đề liên quan