C#反射优化
参考博文
未参考博文
用Emit技术替代反射
C# 之 反射性能优化1 及后续文章
核心代码
public class Property
{
private readonly PropertyGetter getter;
private readonly PropertySetter setter;
public string Name { get; private set; }
public PropertyInfo Info { get; private set; }
public Property(PropertyInfo propertyInfo)
{
if (propertyInfo == null) {
throw new NullReferenceException("属性不能为空");
}
this.Name = propertyInfo.Name;
this.Info = propertyInfo;
this.getter = new PropertyGetter(propertyInfo);
this.setter = new PropertySetter(propertyInfo);
}
public object GetValue(object instance)
{
if (getter != null)
{
return getter.Invoke(instance);
}
return null;
}
public void SetValue(object instance, object value)
{
if (setter != null) {
setter.Invoke(instance, value);
}
}
private class PropertyGetter
{
private readonly Func<object, object> funcGet;
public PropertyGetter(PropertyInfo propertyInfo)
{
if (propertyInfo == null)
{
throw new ArgumentNullException();
}
if (propertyInfo.DeclaringType == null) {
throw new ArgumentNullException();
}
if (propertyInfo.Name == null) {
throw new ArgumentNullException();
}
this.funcGet = CreateGetValueDelegate(propertyInfo.DeclaringType, propertyInfo.Name);
}
private static Func<object, object> CreateGetValueDelegate(Type declaType, String propertyName)
{
var param_instance = Expression.Parameter(typeof(object), "instance");
var body_objToType = Expression.Convert(param_instance, declaType);
var body_getTypeProperty = Expression.Property(body_objToType, propertyName);
var body_return = Expression.Convert(body_getTypeProperty, typeof(object));
return Expression.Lambda<Func<object, object>>(body_return, param_instance).Compile();
}
public object Invoke(object instance)
{
if (funcGet != null) {
return funcGet(instance);
}
return null;
}
}
private class PropertySetter
{
private readonly Action<object, object> setFunc;
public PropertySetter(PropertyInfo propertyInfo)
{
if (propertyInfo == null) {
throw new ArgumentNullException();
}
this.setFunc = CreateSetValueDelegate(propertyInfo);
}
private static Action<object, object> CreateSetValueDelegate(PropertyInfo propertyInfo)
{
var param_instance = Expression.Parameter(typeof(object), "instance");
var param_value = Expression.Parameter(typeof(object), "value");
var body_instance = Expression.Convert(param_instance, propertyInfo.DeclaringType);
var body_value = Expression.Convert(param_value, propertyInfo.PropertyType);
var body_call = Expression.Call(body_instance, propertyInfo.GetSetMethod(), body_value);
return Expression.Lambda<Action<object, object>>(body_call, param_instance, param_value).Compile();
}
public void Invoke(object instance, object value)
{
if (setFunc != null)
{
setFunc(instance, value);
}
}
}
}
性能比较
- 上图假设为读取100行100列的配置
上方为纯赋值1W次,耗时112.38ms,
下方为表达树,需要创建100个(与列数相同)Property类,执行1W次赋值,主要消耗是Property的创建,更具体是PropertySetter和PropertyGetter的创建 - 行数越多,表达树性能越好,上例中,行数为87时,两者性能相当,行数少纯赋值好,行数多表达树好
- 读取配置时,只需要属性赋值,可以不初始化PropertyGetter,表达树性能更好,行数超过50便好于纯赋值
其他
- 感觉涉及到动态代码生成,未测试ios是否支持
- 只支持属性Property,不支持字段FieldInfo
- Invoke(object instance, object value)的instance是引用类型,应该没有装箱拆箱
但value一般是值类型,会有装箱拆箱操作,不过也还好吧