[英]CreateDelegate instead of Reflection for SetValue
我試圖實現Jon Skeet針對此博客文章上發布的問題的解決方案,以使用代表的非反射方法替換SetValue
方法。
與博客文章中的解決方案的不同之處在於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);
行上的異常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;
}
}
當你不想打電話給像喬恩斯基特任意方法,則可以簡化你的代碼了很多 。 無需在代碼中調用MethodInfo.Invoke
,因此不需要委托。 您可以直接在返回的PropertyInfo
上直接調用SetValue
。 無需使用委托的彎路,而該委托反過來又會准確地調用該方法。 另外,類型轉換不是必需的,因為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%。
由於在呼叫鏈中避免了兩個不必要的委托,因此性能略有提高。 但是,速度改進的絕大部分在於我們刪除了類型轉換。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.