2013-07-02 2 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 수집은 정적 또는 인덱싱 된 속성을 포함하지 않는다 그러나 나는 그러나 같은 intdouble 같은 값 형식의 속성에 대한 작업이 필요합니까 .

내 코드를 추상화하고 제네릭을 피하면서 필요한 getter/setter를 어떻게 만들 수 있습니까?

+0

? 그리고 정확히 언제이 예외가 생깁니 까? –

+0

포함 된 코드에 속성 컬렉션 정의를 추가했습니다. 코드가 유형에서 실행될 때 예외가 발생합니다. –

+0

이 코드 줄을 추가하여 예외가 발생할 수 있습니다. 또한 사전을 어떻게 사용할 것인지 이해하는 데 도움이됩니다. –

답변

7

확인이 질문에서 내 대답을 찾는 결국 : MethodInfo.Invoke performance issue

더 구체적으로이 문서 :

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)); 
    } 
} 
: 여기 Making reflection fly and exploring delegates

내가 함께 결국 코드의 JIST입니다

생성 된 델리게이트는 리플렉션을 사용하는 것보다 평균 80 % 빠르므로 그 결과에 만족합니다!

+1

위 기사에서 도움이 되었기 때문에 유용합니다! –

-1

동일한 오류가 발생했습니다. 이 문제를 해결하기 위해 표현식 API을 사용했습니다.

참고 : 참조 할 방법은 일반적인

  • 없습니다.
  • 은 정적입니다.

위임 이름이 공식은 다음과 같이 그 서명은

public delegate float Formula(Dictionary<string, float> cr, 
           List<Dictionary<string, float>> allr); 
  1. Assembly assembly = results.CompiledAssembly; 
    var generatedType = assembly.GetType("First.NewClass"); 
    var generatedMethod = generatedType.GetMethod("FormulaMethod"); 
    
  2. 하는 매개 변수로 위임의 인수를 준비 위임로 참조 될 MethodInfo를 가져옵니다 표현. 인수 1 Dictionary<string, float> 인수 2 List<Dictionary<string, float>>

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

    VAR arg2Expression = Expression.Parameter (대해서 typeof (일람>));

  3. 마지막 메서드를 생성하여 Expression을 호출하고 대리자를 반환합니다.당신은`Properties`을 만들려면 어떻게해야합니까

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