Не удается выполнить привязку к целевому методу при создании делегатов для свойств
попытка создать два словаря испускаемых делегатов для повышения производительности при динамическом получении / настройке значений свойств.
код:
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
коллекция не содержит статических или индексированных свойств, но мне это нужно для работы со свойствами типа значения, такими как int
и double
.
как я могу создать геттеры / сеттеры, которые мне нужны, сохраняя абстрактный код и избегая дженериков?
2 ответов
Ok в конечном итоге нашел мой ответ на этот вопрос: объект methodinfo.Вызовите проблему производительности
более конкретно эта статья: сделать отражение летать и исследовать делегатов
вот суть кода, который я закончил с:
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% быстрее, чем с помощью отражения, поэтому я доволен результатом!
Я получал ту же ошибку. Я использовал выражения API исправить эту проблему.
Примечание : метод ссылка
- не универсальный.
- это статическое.
имя делегата-формула, и его подпись выглядит следующим образом
public delegate float Formula(Dictionary<string, float> cr,
List<Dictionary<string, float>> allr);
-
Get MethodInfo, на который следует ссылаться как на Delegate
Assembly assembly = results.CompiledAssembly; var generatedType = assembly.GetType("First.NewClass"); var generatedMethod = generatedType.GetMethod("FormulaMethod");
-
подготовьте аргументы делегата в качестве параметра Выражение. Аргумент 1 :
Dictionary<string, float>
Аргумент 2 :List<Dictionary<string, float>>
var arg1Expression = Expression.Parameter(typeof(Dictionary<string, float>));
var arg2Expression = выражение.Параметр (typeof (List>));
-
сгенерировать выражение окончательного вызова метода и делегат возврата.
var methodCall = Expression.Call(generatedMethod, arg1Expression, arg2Expression); return Expression.Lambda <Formula> (methodCall, arg1Expression, arg2Expression).Compile();