I tried to implement Jon Skeet's solution for this question posted on this blog post to substitute the SetValue
method with a non-reflection method using delegates.
The difference from the solution in the blog post is that SetValue
is void
, and I get the The type 'System.Void' may not be used as a type argument.
exception at the line MethodInfo miConstructedHelper = miGenericHelper.MakeGenericMethod(typeof(G), pMethod.GetParameters()[0].ParameterType, pMethod.ReturnType);
.
Here's my implementation of the 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;
}
}
You are using
Func
in your code.Func
is for methods that have a return type. For methods that returnvoid
you need to useAction
.Your code needs to look like this:
As you don't want to call arbitrary methods like Jon Skeet, you can simplify your code a lot. There is no need for a call to
MethodInfo.Invoke
in your code and because of this there is no need for the delegates. You can simply callSetValue
directly on the returnedPropertyInfo
. There is no need to use the detour of a delegate that in turn calls exactly that method anyway. Additionally, the type conversion is not necessary asSetValue
requires anobject
anyway.Your code could be as simple as this:
Performance tests show that this version takes only about 50% of the previous one.
A tiny increase in performance is due to the fact that we avoid two unnecessary delegates in our call chain. However, the vast majority of the speed improvement lays in the fact that we removed the type conversion.