gpt4 book ai didi

c# - CreateDelegate 而不是 SetValue 的反射

转载 作者:太空狗 更新时间:2023-10-30 00:54:25 26 4
gpt4 key购买 nike

我尝试为 this question 实现 Jon Skeet 的解决方案发布在此 blog postSetValue 方法替换为使用委托(delegate)的非反射方法。

blog post中解决方案的区别SetValuevoid,我得到 The type 'System.Void' may not be used as a type argument. 异常行 MethodInfo miConstructedHelper = miGenericHelper.MakeGenericMethod(typeof(G), pMethod.GetParameters()[0].ParameterType, pMethod.ReturnType);

这是我对 MagicMethod 的实现:

public class Instantiator<T> where T : new()
{
private T instance;
private IDictionary<string, PropertyInfo> properties;

private Func<PropertyInfo, object, object> _fncSetValue;

public Instantiator()
{
Type type = typeof(T);
properties = type.GetProperties().GroupBy(p => p.Name).ToDictionary(g => g.Key, g => g.ToList().First());

MethodInfo miSetValue = typeof(PropertyInfo).GetMethod("SetValue", new Type[] { typeof(object), typeof(object), typeof(object[]) });
_fncSetValue = SetValueMethod<PropertyInfo>(miSetValue);
}

public void CreateNewInstance()
{
instance = new T();
}

public void SetValue(string pPropertyName, object pValue)
{
if (pPropertyName == null) return;
PropertyInfo property;
if (!properties.TryGetValue(pPropertyName, out property)) return;
TypeConverter tc = TypeDescriptor.GetConverter(property.PropertyType);

//substitute this line
//property.SetValue(instance, tc.ConvertTo(pValue, property.PropertyType), null);
//with this line
_fncSetValue(property, new object[] { instance, tc.ConvertTo(pValue, property.PropertyType), null });
}

public T GetInstance()
{
return instance;
}

private static Func<G, object, object> SetValueMethod<G>(MethodInfo pMethod) where G : class
{
MethodInfo miGenericHelper = typeof(Instantiator<T>).GetMethod("SetValueMethodHelper", BindingFlags.Static | BindingFlags.NonPublic);
MethodInfo miConstructedHelper = miGenericHelper.MakeGenericMethod(typeof(G), pMethod.GetParameters()[0].ParameterType, pMethod.ReturnType);
object retVal = miConstructedHelper.Invoke(null, new object[] { pMethod });
return (Func<G, object, object>) retVal;
}

private static Func<TTarget, object, object> SetValueMethodHelper<TTarget, TParam, TReturn>(MethodInfo pMethod) where TTarget : class
{
Func<TTarget, TParam, TReturn> func = (Func<TTarget, TParam, TReturn>)Delegate.CreateDelegate(typeof(Func<TTarget, TParam, TReturn>), pMethod);
Func<TTarget, object, object> retVal = (TTarget target, object param) => func(target, (TParam) param);
return retVal;
}
}

最佳答案

您正在代码中使用 FuncFunc 适用于具有返回类型的方法。对于返回 void 的方法,您需要使用 Action


您的代码需要如下所示:

public class Instantiator<T> where T : new()
{
private T instance;
private IDictionary<string, PropertyInfo> properties;

private Action<PropertyInfo, object, object, object> _fncSetValue;

public Instantiator()
{
Type type = typeof(T);
properties = type.GetProperties()
.GroupBy(p => p.Name)
.ToDictionary(g => g.Key, g => g.ToList().First());

var types = new Type[] { typeof(object), typeof(object),
typeof(object[]) };
var miSetValue = typeof(PropertyInfo).GetMethod("SetValue", types);
_fncSetValue = SetValueMethod<PropertyInfo>(miSetValue);
}

public void CreateNewInstance()
{
instance = new T();
}

public void SetValue(string pPropertyName, object pValue)
{
if (pPropertyName == null) return;
PropertyInfo property;
if (!properties.TryGetValue(pPropertyName, out property)) return;
TypeConverter tc = TypeDescriptor.GetConverter(property.PropertyType);

var value = tc.ConvertTo(pValue, property.PropertyType);
_fncSetValue(property, instance, value, null);
}

public T GetInstance()
{
return instance;
}

private static Action<G, object, object, object> SetValueMethod<G>(MethodInfo pMethod) where G : class
{
var miGenericHelper =
typeof(Instantiator<T>).GetMethod("SetValueMethodHelper",
BindingFlags.Static |
BindingFlags.NonPublic);

var parameters = pMethod.GetParameters();
var miConstructedHelper = miGenericHelper.MakeGenericMethod(typeof(G),
parameters[0].ParameterType,
parameters[1].ParameterType,
parameters[2].ParameterType);

var retVal = miConstructedHelper.Invoke(null, new object[] { pMethod });
return (Action<G, object, object, object>) retVal;
}

private static Action<TTarget, object, object, object> SetValueMethodHelper<TTarget, TParam1, TParam2, TParam3>(MethodInfo pMethod) where TTarget : class
{
var func = (Action<TTarget, TParam1, TParam2, TParam3>)Delegate.CreateDelegate(typeof(Action<TTarget, TParam1, TParam2, TParam3>), pMethod);
Action<TTarget, object, object, object> retVal =
(target, param1, param2, param3) =>
func(target, (TParam1) param1, (TParam2) param2, (TParam3) param3);

return retVal;
}
}

因为您不想像 Jon Skeet 那样调用任意方法,所以您可以大大 简化您的代码。无需在您的代码中调用 MethodInfo.Invoke,因此不需要委托(delegate)。您可以直接对返回的 PropertyInfo 调用 SetValue。无需绕过委托(delegate),而委托(delegate)又会调用该方法。此外,类型转换不是必需的,因为 SetValue 无论如何都需要一个 object
您的代码可以像这样简单:

public class SimpleInstantiator<T> where T : new()
{
private T instance;
private IDictionary<string, PropertyInfo> properties;

public SimpleInstantiator()
{
Type type = typeof(T);
properties = type.GetProperties()
.GroupBy(p => p.Name)
.ToDictionary(g => g.Key, g => g.ToList().First());
}

public void CreateNewInstance()
{
instance = new T();
}

public void SetValue(string pPropertyName, object pValue)
{
if (pPropertyName == null) return;

PropertyInfo property;
if (!properties.TryGetValue(pPropertyName, out property)) return;

property.SetValue(instance, pValue, null);
}

public T GetInstance()
{
return instance;
}
}

性能测试表明,这个版本只占用了上一个版本的50%左右。
性能的微小提升是由于我们在调用链中避免了两个不必要的委托(delegate)。然而,绝大多数速度改进在于我们删除了类型转换这一事实。

关于c# - CreateDelegate 而不是 SetValue 的反射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12968932/

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