力图打造发射代表了两个词典,以便提高性能时,动态获取/设置属性的值。
Trying to create two dictionaries of emitted delegates to allow for improved performance when dynamically getting/setting the values of properties.
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()));
不过,我得到以下异常:
However I get the following exception:
无法绑定到目标方法,因为其签名或安全 透明度不与委托类型兼容。
Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
从我读这会被静电/索引/值类型属性引起的,属性
collection不包含静态或索引的属性,但是,但是我确实需要这为值类型的属性,如 INT
和双
。
From what I have read this will be caused by static/indexed/value type properties, the Properties
collection contains no static or indexed properties but I do however need this to work for value type properties such as int
and double
.
我怎样才能创建的getter /我需要同时保持我的code抽象,避免仿制药制定者?
How can I create the getters/setters that I need while keeping my code abstract and avoiding generics?
确定最终从这个问题找到我的答案: MethodInfo.Invoke 性能问题
Ok ended up finding my answer from this question: MethodInfo.Invoke performance issue
更具体的这篇文章: 使反射飞翔和探索代表
More specifically this article: Making reflection fly and exploring delegates
下面是我结束了在code中的JIST:
Here is the jist of the code that I ended up with:
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%,所以我很高兴的结果!
The generated delegates on average seem to be 80% faster than using reflection, so I am happy with the result!