我正在使用以下代码创建和缓存属性访问者委托:
static Delegate CreateGetterDelegate<T>(PropertyInfo propertyInfo)
{
if (typeof(T) != propertyInfo.DeclaringType)
{
throw new ArgumentException();
}
var instance = Expression.Parameter(propertyInfo.DeclaringType);
var property = Expression.Property(instance, propertyInfo);
var convert = Expression.TypeAs(property, typeof(object));
return (Func<T, object>)Expression.Lambda(convert, instance).Compile();
}
这工作正常并且运行良好(谢谢StackOverflow!),但是我想通过返回T和对象的Func来删除所需的装箱/拆箱。有没有办法改变返回值,以便返回类型是T的Func和typeofproperty?
即。
static Delegate CreateGetterDelegate<T>(PropertyInfo propertyInfo)
{
if (typeof(T) != propertyInfo.DeclaringType)
{
throw new ArgumentException();
}
... some magic happening here ...
return (Func<T, typeofproperty>)Expression.Lambda(...more magic...).Compile();
}
注意 - 我正在使用VS2013和.NET 4.5
答案 0 :(得分:5)
唯一的方法是在编译时知道属性的类型,无论是在此方法定义中还是在调用者中。如果此方法的调用者知道属性的类型,那么它可以使用第二个泛型参数指定它:
static Func<TInstance, TResult> CreateGetterDelegate<TInstance, TResult>(
PropertyInfo propertyInfo)
{
if (typeof(TInstance) != propertyInfo.DeclaringType)
{
throw new ArgumentException();
}
var instance = Expression.Parameter(propertyInfo.DeclaringType);
var property = Expression.Property(instance, propertyInfo);
var convert = Expression.TypeAs(property, typeof(object));
return (Func<TInstance, TResult>)Expression.Lambda(convert, instance)
.Compile();
}
当然,这只是将问题推回给调用者。如果连呼叫者都不知道该属性的类型,那么他们就会遇到完全相同的问题。
在一天结束时,为了避免装箱某些代码需要在编译时知道 这个属性的类型是什么。如果有人在某个地方,在编译时就会知道,那么你可以继续使用泛型来解决问题,直到你达到某个人可以使用实际已知类型的那一点。如果在编译时什么都不知道类型,那么这个问题确实没有任何解决方案。
你可能,如果你想获得技术,可以通过使事物比它们更加动态来避免拳击(使用反射来调用这些使用反射来做事物的方法)但是从技术的角度来看,你可以能够避免文字box
命令,你会失去比你获得的更多的方式。它不是一个实用的解决方案。
答案 1 :(得分:0)
上面关于再次使用反射的评论让我思考(总是一个危险的前景),我提出了以下解决方案,基本上实现了Servy的建议:
static Delegate CreateGenericGetterDelegate<TClass>(PropertyInfo propertyInfo)
{
var method = typeof(Cache).GetMethod("CreateTypedGetterDelegate");
MethodInfo generic = method.MakeGenericMethod(new Type[] { typeof(TClass), propertyInfo.PropertyType });
return (Delegate) generic.Invoke(new object(), new object[] { propertyInfo });
}
public static Delegate CreateTypedGetterDelegate<TClass, TProp>(PropertyInfo propertyInfo)
{
if (typeof(TClass) != propertyInfo.DeclaringType)
{
throw new ArgumentException();
}
var instance = Expression.Parameter(propertyInfo.DeclaringType);
var property = Expression.Property(instance, propertyInfo);
if (typeof(TProp).IsValueType)
{
return (Func<TClass, TProp>)Expression.Lambda(property, instance).Compile();
}
else
{
return (Func<TClass, TProp>)Expression.Lambda(Expression.TypeAs(property, typeof(TProp)), instance).Compile();
}
}
这项工作,提供类型安全的访问,并避免任何明显的装箱/拆箱。由于这是在我的程序开始时发生的一次(并且仅针对实际访问的属性),我可以使用反射的性能命中,以换取属性访问器的类型代理。