2013-07-02 42 views
8

Cố gắng tạo hai từ điển của các đại biểu được phát ra để cho phép cải thiện hiệu suất khi tự động nhận/thiết lập các giá trị của thuộc tính.Không thể liên kết với phương pháp đích khi tạo đại biểu cho các thuộc tính

Code:

Properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) 
        .Where(p => p.CanRead && !p.GetIndexParameters().Any()) 
        .AsEnumerable(); 
    PropertyGetters = Properties.ToDictionary(p => p.Name, p => (Func<object, object>)Delegate.CreateDelegate(typeof(Func<object, object>), p.GetGetMethod())); 
    PropertySetters = Properties.Where(p => p.GetSetMethod() != null) 
        .ToDictionary(p => p.Name, p => (Action<object, object>)Delegate.CreateDelegate(typeof(Action<object, object>), p.GetSetMethod())); 

Tuy nhiên tôi nhận được ngoại lệ sau đây:

Không thể liên kết với các phương pháp mục tiêu vì chữ ký của mình, an ninh minh bạch là không tương thích với điều đó của các loại đại biểu.

Từ những gì tôi đã đọc điều này sẽ được gây ra bởi các thuộc tính tĩnh/lập chỉ mục/kiểu giá trị, bộ sưu tập Properties không chứa các thuộc tính tĩnh hoặc lập chỉ mục nhưng tuy nhiên tôi cần điều này để làm việc cho loại giá trị tài sản như intdouble .

Làm cách nào để tạo các getters/setters mà tôi cần trong khi vẫn giữ mã của mình trừu tượng và tránh các generics?

+0

Làm cách nào để bạn tạo 'Thuộc tính'? Và khi nào bạn nhận được ngoại lệ này? –

+0

Đã thêm định nghĩa tập hợp thuộc tính vào mã được bao gồm, tôi nhận được ngoại lệ khi mã được thực thi trên một loại. –

+0

Bạn có thể muốn thêm dòng mã này, nơi bạn nhận được một ngoại lệ. nó cũng sẽ giúp hiểu, làm thế nào bạn sẽ sử dụng những từ điển đó. –

Trả lời

7

Ok đã kết thúc việc tìm kiếm câu trả lời của tôi từ câu hỏi này: MethodInfo.Invoke performance issue

Cụ thể hơn bài viết này: Making reflection fly and exploring delegates

Đây là jist của mã mà tôi đã kết thúc với:

public class Helper 
{ 
    private IDictionary<string, Func<object, object>> PropertyGetters { get; set; } 

    private IDictionary<string, Action<object, object>> PropertySetters { get; set; } 

    public static Func<object, object> CreateGetter(PropertyInfo property) 
    { 
     if (property == null) 
      throw new ArgumentNullException("property"); 

     var getter = property.GetGetMethod(); 
     if (getter == null) 
      throw new ArgumentException("The specified property does not have a public accessor."); 

     var genericMethod = typeof(Helper).GetMethod("CreateGetterGeneric"); 
     MethodInfo genericHelper = genericMethod.MakeGenericMethod(property.DeclaringType, property.PropertyType); 
     return (Func<object, object>)genericHelper.Invoke(null, new object[] { getter }); 
    } 

    public static Func<object, object> CreateGetterGeneric<T, R>(MethodInfo getter) where T : class 
    { 
     Func<T, R> getterTypedDelegate = (Func<T, R>)Delegate.CreateDelegate(typeof(Func<T, R>), getter); 
     Func<object, object> getterDelegate = (Func<object, object>)((object instance) => getterTypedDelegate((T)instance)); 
     return getterDelegate; 
    } 

    public static Action<object, object> CreateSetter(PropertyInfo property) 
    { 
     if (property == null) 
      throw new ArgumentNullException("property"); 

     var setter = property.GetSetMethod(); 
     if (setter == null) 
      throw new ArgumentException("The specified property does not have a public setter."); 

     var genericMethod = typeof(Helper).GetMethod("CreateSetterGeneric"); 
     MethodInfo genericHelper = genericMethod.MakeGenericMethod(property.DeclaringType, property.PropertyType); 
     return (Action<object, object>)genericHelper.Invoke(null, new object[] { setter }); 
    } 

    public static Action<object, object> CreateSetterGeneric<T, V>(MethodInfo setter) where T : class 
    { 
     Action<T, V> setterTypedDelegate = (Action<T, V>)Delegate.CreateDelegate(typeof(Action<T, V>), setter); 
     Action<object, object> setterDelegate = (Action<object, object>)((object instance, object value) => { setterTypedDelegate((T)instance, (V)value); }); 
     return setterDelegate; 
    } 

    public Helper(Type type) 
    { 
     var Properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance) 
        .Where(p => p.CanRead && !p.GetIndexParameters().Any()).AsEnumerable(); 
     PropertyGetters = Properties.ToDictionary(p => p.Name, p => CreateGetter(p)); 
     PropertySetters = Properties.Where(p => p.GetSetMethod() != null) 
      .ToDictionary(p => p.Name, p => CreateSetter(p)); 
    } 
} 

Các đại biểu được tạo trung bình dường như nhanh hơn 80% so với sử dụng phản ánh, vì vậy tôi hài lòng với kết quả!

+1

Rất vui được tìm thấy lợi ích từ bài viết trên! –

-1

Tôi đã gặp lỗi tương tự. Tôi đã sử dụng API biểu thức để khắc phục sự cố này.

Lưu ý: Phương pháp để được tham chiếu là

  • không chung chung.
  • là tĩnh.

tên đại biểu là công thức và chữ ký của nó là như sau

public delegate float Formula(Dictionary<string, float> cr, 
           List<Dictionary<string, float>> allr); 
  1. Nhận MethodInfo mà là để được tham chiếu như là Đại biểu

    Assembly assembly = results.CompiledAssembly; 
    var generatedType = assembly.GetType("First.NewClass"); 
    var generatedMethod = generatedType.GetMethod("FormulaMethod"); 
    
  2. Chuẩn bị lập luận của các đại biểu như Parameter Biểu hiện. Đối số 1: Dictionary<string, float> Đối số 2: List<Dictionary<string, float>>

    var arg1Expression = Expression.Parameter(typeof(Dictionary<string, float>)); 
    

    var arg2Expression = Expression.Parameter (typeof (Danh mục>));

  3. Tạo phương thức cuối cùng Biểu thức cuộc gọi và trả lại Đại biểu.

    var methodCall = Expression.Call(generatedMethod, 
               arg1Expression, 
               arg2Expression); 
    
    return Expression.Lambda <Formula> (methodCall, 
                arg1Expression, 
                arg2Expression).Compile(); 
    
Các vấn đề liên quan