- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我尝试为 this question 实现 Jon Skeet 的解决方案发布在此 blog post将 SetValue
方法替换为使用委托(delegate)的非反射方法。
与blog post中解决方案的区别SetValue
是 void
,我得到 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;
}
}
最佳答案
您正在代码中使用 Func
。 Func
适用于具有返回类型的方法。对于返回 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/
我正在尝试创建委托(delegate)以在运行时读取/写入未知类型类的属性。 我有一个通用类 Main和一个看起来像这样的方法: Delegate.CreateDelegate(typeof(Func
这是 prior thread 的一种后续。我正在构建一个小型包装器来向上调用我的用户提供的动态类型化方法。该方案运作良好......但仅适用于静态方法。尽管 CreateDelegate 也应该适用
感谢 Jon Skeet 在 this 中的回答问题我有以下工作: public delegate BaseItem GetItemDelegate(Guid itemID); public stat
假设我想传递一个成员函数作为回调。 我应该使用什么来传递上下文 - bind() 或 createDelegate()? 我的意思是,这个: someObj.on('someEvent', this.
我有以下问题:我想调用 Delegate.CreateDelegate从我针对 .NET 4.5、Windows Phone 8 和 Windows 8 商店应用程序的可移植类库中,但我的代码无法编译
我一直在尝试使用反射来比较在编译时类型未知的对象,而不是每次尝试使用 CreateDelegate() 时都调用 Invoke()。到目前为止,我已经在基本类型等的通用类型类中使用它,但我遇到了类型为
这是我第一次尝试将用户定义的参数传递给 IE9 中 extjs(4.0.1) 中的处理程序函数。我有以下代码,但它抛出了一个错误,指出 SCRIPT438: Object doesn't suppor
这是我第一次尝试将用户定义的参数传递给 IE9 中 extjs(4.0.1) 中的处理程序函数。我有以下代码,但它抛出了一个错误,指出 SCRIPT438: Object doesn't suppor
使用 Jon Skeet 的文章 Making reflection fly and exploring delegates作为指南,我正在尝试使用 Delegate.CreateDelegate 方
在创建接口(interface)方法的委托(delegate)时,我正在努力寻找哪里出错了 我的代码如下: private static Func> FindScrapeMethod(ICrawler
编辑:我在 microsoft connect::上提交了错误报告: https://connect.microsoft.com/VisualStudio/feedback/details/61423
现在,我必须这样做 private delegate void set(int obj); //declare the prototype ... Delegate delegate1 = Deleg
我尝试为 this question 实现 Jon Skeet 的解决方案发布在此 blog post将 SetValue 方法替换为使用委托(delegate)的非反射方法。 与blog post中
我正在尝试使用 Delegate.CreateDelegate [MSDN link]绑定(bind)到静态泛型方法,但绑定(bind)失败。这是 PoC 代码: public static clas
我在看的实现 Observable.FromEvent(add, remove) 我正在努力了解它是如何工作的。让我们说 TEventHandler 是标准: public delegate void
我有一个静态方法: public class Example { //for demonstration purposes - just returns default(T) publ
关于Making reflection fly and exploring delegates的问题... 如果我需要创建委托(delegate) Func我可能会使用的动态加载类型的方法 (1) D
当我调用 CreateDelegate(delegateType) 时,我得到一个 System.ArgumentException,根据 MSDN,这是因为 delegateType 的参数数量错误
在遵循这个问题的答案后,我发现我必须使用 ref 参数来调用结构上的实例方法。 How can I create an open Delegate from a struct's instance m
运行 Run2 方法。但是Run方法没有运行。是什么原因 ?两种方法之间的唯一区别是因为参数。 public class MyClass { public string Name { get;
我是一名优秀的程序员,十分优秀!