gpt4 book ai didi

c# - 为属性 setter 或 getter 创建一个高性能的开放委托(delegate)

转载 作者:可可西里 更新时间:2023-11-01 07:55:14 25 4
gpt4 key购买 nike

开放委托(delegate)是对没有目标的实例方法的委托(delegate)。要调用它,您需要提供目标作为它的第一个参数。它们是优化代码的聪明方法,否则会使用反射并导致性能不佳。有关开放委托(delegate)的介绍,请参阅 this .您在实践中使用它的方式是使用昂贵的反射代码来构建这些开放的委托(delegate),但是您可以像简单的委托(delegate)调用一样非常便宜地调用它们。

我正在尝试编写代码,将任意 PropertyInfo 转换为其 setter 的此类委托(delegate)。到目前为止,我想出了这个:

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 委托(delegate)使用 DynamicInvoke 从 Action <derivedType 转换> 行动 <object >,我怀疑这是我所追求的优化的很大一部分。所以问题是:

  1. DynamicInvoke 真的值得关注吗?
  2. 它周围有什么吗?

最佳答案

DynamicInvoke 不会成为高性能的 setter。此处针对通用内部类型的反射是您更好的选择,因为这将允许您使用typed 委托(delegate)。另一种选择是 DynamicMethod,但您需要担心一些 IL 细节。

可能想看看HyperDescriptor,它将 IL 工作包装到 PropertyDescriptor 实现中。另一种选择是 Expression API(如果您使用的是 .NET 3.5 或更高版本):

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;
}
}

关于c# - 为属性 setter 或 getter 创建一个高性能的开放委托(delegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4085798/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com