Creating an performant open delegate for an property setter or getter(为属性设置器或获取器创建高性能开放委托)
问题描述
开放委托是对没有目标的实例方法的委托.要调用它,您需要提供目标作为其第一个参数.它们是一种优化代码的聪明方法,否则会使用反射并且性能很差.有关公开代表的介绍,请参阅 this.您在实践中使用它的方式是使用昂贵的反射代码来构建这些开放的委托,但是您可以通过简单的委托调用非常便宜地调用它们.
An open delegate is a delegate to an instance method without the target. To call it you supply the target as its first parameter. They are a clever way to optimize code that otherwise would use reflection and have poor performance. For an intro to open delegates see this. The way you would use it in practice is to have expensive reflection code to build these open delegates, but then you would be able to call them very cheaply as a simple Delegate call.
我正在尝试编写将任意 PropertyInfo 转换为它的 setter 的委托的代码.到目前为止,我想出了这个:
I'm trying to write code that will transform an arbitrary PropertyInfo, into such an delegate for its setter. So far I came up with this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace Test
{
class TestClass
{
static Action<T, object> MakeSetterDelegate<T>(PropertyInfo property)
{
MethodInfo setMethod = property.GetSetMethod();
if (setMethod != null && setMethod.GetParameters().Length == 1) //skips over nasty index properties
{
//To be able to bind to the delegate we have to create a delegate
//type like: Action<T,actualType> rather than Action<T,object>.
//We use reflection to do that
Type setterGenericType = typeof(Action<,>);
Type delegateType = setterGenericType.MakeGenericType(new Type[] { typeof(T), property.PropertyType });
var untypedDelegate = Delegate.CreateDelegate(delegateType, setMethod);
//we wrap the Action<T,actualType> delegate into an Action<T,object>
Action<T, object> setter = (instance, value) =>
{
untypedDelegate.DynamicInvoke(new object[] { instance, value });
};
return setter;
}
else
{
return null;
}
}
int TestProp
{
set
{
System.Diagnostics.Debug.WriteLine("Called set_TestProp");
}
}
static void Test()
{
PropertyInfo property = typeof(TestClass).GetProperty("TestProp");
Action<TestClass, object> setter = MakeSetterDelegate<TestClass>(property);
TestClass instance = new TestClass();
setter(instance, 5);
}
}
}
将为 getter 编写类似的代码.它可以工作,但是 setter 委托使用 DynamicInvoke 将 Action<derivedType
> 转换为 Action<object
>,我怀疑这会占用很大一部分我追求的优化.所以问题是:
Similar code would be written for the getter. It works, but the setter delegate uses a DynamicInvoke to convert from an Action<derivedType
> to Action<object
>, which I suspect is eating a good part of the optimization I'm after. So the questions are:
- DynamicInvoke 真的值得关注吗?
- 周围有吗?
推荐答案
DynamicInvoke
不会成为高性能的 setter.对泛型内部类型的反射是您更好的选择,因为这将允许您使用 typed 委托.另一种选择是DynamicMethod
,但是你需要担心一些IL细节.
DynamicInvoke
will not make a performant setter. Reflection against a generic inner type is your better option here, as this will allow you to use typed delegates. Another option is DynamicMethod
, but then you need to worry about a few IL details.
您可能想查看 HyperDescriptor
,它将 IL 工作包装到 PropertyDescriptor
实现中.另一种选择是 Expression
API(如果您使用的是 .NET 3.5 或更高版本):
You might want to look at HyperDescriptor
, which wraps up the IL work into a PropertyDescriptor
implementation. Another option is the Expression
API (if you are using .NET 3.5 or above):
static Action<T, object> MakeSetterDelegate<T>(PropertyInfo property)
{
MethodInfo setMethod = property.GetSetMethod();
if (setMethod != null && setMethod.GetParameters().Length == 1)
{
var target = Expression.Parameter(typeof(T));
var value = Expression.Parameter(typeof(object));
var body = Expression.Call(target, setMethod,
Expression.Convert(value, property.PropertyType));
return Expression.Lambda<Action<T, object>>(body, target, value)
.Compile();
}
else
{
return null;
}
}
或者使用泛型类型:
abstract class Setter<T>
{
public abstract void Set(T obj, object value);
}
class Setter<TTarget, TValue> : Setter<TTarget>
{
private readonly Action<TTarget, TValue> del;
public Setter(MethodInfo method)
{
del = (Action<TTarget, TValue>)
Delegate.CreateDelegate(typeof(Action<TTarget, TValue>), method);
}
public override void Set(TTarget obj, object value)
{
del(obj, (TValue)value);
}
}
static Action<T, object> MakeSetterDelegate<T>(PropertyInfo property)
{
MethodInfo setMethod = property.GetSetMethod();
if (setMethod != null && setMethod.GetParameters().Length == 1)
{
Setter<T> untyped = (Setter<T>) Activator.CreateInstance(
typeof(Setter<,>).MakeGenericType(typeof(T),
property.PropertyType), setMethod);
return untyped.Set;
}
else
{
return null;
}
}
这篇关于为属性设置器或获取器创建高性能开放委托的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:为属性设置器或获取器创建高性能开放委托
基础教程推荐
- 如何激活MC67中的红灯 2022-01-01
- MS Visual Studio .NET 的替代品 2022-01-01
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01
- c# Math.Sqrt 实现 2022-01-01
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30
- 将 XML 转换为通用列表 2022-01-01
- SSE 浮点算术是否可重现? 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01