2013-07-02 33 views
8

試圖創建兩個發出委託的字典,以便在動態獲取/設置屬性值時提高性能。在爲屬性創建委託時,無法綁定到目標方法

代碼:

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

但是我得到以下異常:

無法綁定到目標的方法,因爲它的簽名或安全 透明度不與委託類型兼容。

從我讀這將通過靜態/索引/值類型屬性引起的Properties collection不包含靜態或索引屬性,但然而,我需要這個值類型的屬性,例如intdouble工作。

如何在保留代碼抽象和避免泛型的同時創建需要的getters/setters?

+0

如何創建'Properties'?什麼時候你會得到這個異常? –

+0

將屬性集合定義添加到包含的代碼中,當代碼在類型上執行時,我得到異常。 –

+0

您可能需要添加以下代碼行,您會在那裏得到異常。它也將有助於理解,你將如何使用這些字典。 –

回答

7

好結束了,從這個問題找到我的答案: MethodInfo.Invoke performance issue

更具體的這篇文章: Making reflection fly and exploring delegates

這裏是我結束了代碼的JIST:

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

平均生成的代表似乎比使用反射快80%,所以我對結果感到滿意!

+1

時使用它們很高興您從上面的文章中獲益! –

-1

我得到同樣的錯誤。我用表達式API來解決這個問題。

注:方法中引用的是

  • 不是通用的。
  • 是靜態的。

代表的名字是公式及其簽名如下

public delegate float Formula(Dictionary<string, float> cr, 
           List<Dictionary<string, float>> allr); 
  1. 獲取MethodInfo的是不如授人以被引用

    Assembly assembly = results.CompiledAssembly; 
    var generatedType = assembly.GetType("First.NewClass"); 
    var generatedMethod = generatedType.GetMethod("FormulaMethod"); 
    
  2. 準備委託作爲參數的參數表達。 參數1:Dictionary<string, float> 參數2:List<Dictionary<string, float>>

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

    變種arg2Expression = Expression.Parameter(typeof運算(列表>));

  3. 生成最終方法調用表達式並返回委託。

    var methodCall = Expression.Call(generatedMethod, 
               arg1Expression, 
               arg2Expression); 
    
    return Expression.Lambda <Formula> (methodCall, 
                arg1Expression, 
                arg2Expression).Compile(); 
    
相關問題