createDelegate方法,而不是用于思考的SetValue [英] CreateDelegate instead of Reflection for SetValue

查看:88
本文介绍了createDelegate方法,而不是用于思考的SetValue的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图执行乔恩斯基特对这个问题发布在这个博客文章来替代的SetValue 方法,使用委托非反射法。



从溶液区别在博客文章的SetValue 无效,我也得到了类型'系统。太虚不能用作类型参数。 MethodInfo的miConstructedHelper = miGenericHelper.MakeGenericMethod(typeof运算(G),pMethod.GetParameters()异常的行[0] .ParameterType ,pMethod.ReturnType);



下面是我执行 MagicMethod

 公共类实例化< T>其中T:新的()
{
私人牛逼实例;
私人的IDictionary<字符串的PropertyInfo>性能;

私人Func键<的PropertyInfo,对象,对象> _fncSetValue;

公共实例化()
{$ B $型B型= typeof运算(T);
属性= type.GetProperties()GROUPBY(p值=> p.Name).ToDictionary(G => g.Key,G =方式> g.ToList()第一());

MethodInfo的miSetValue = typeof运算(的PropertyInfo).GetMethod(的SetValue,新类型[] {typeof运算(对象)的typeof(对象)的typeof(对象[])});
_fncSetValue = SetValueMethod<&的PropertyInfo GT;(miSetValue);
}

公共无效CreateNewInstance()
{
实例=新T();
}

公共无效的SetValue(字符串pPropertyName,对象P值)
{
如果(pPropertyName == NULL)回报;
的PropertyInfo财产;
如果回报(properties.TryGetValue(pPropertyName,出物业)!);
TypeConverter的TC = TypeDescriptor.GetConverter(property.PropertyType);

//替代这一行
//property.SetValue(instance,tc.ConvertTo(P值,property.PropertyType),NULL);
//这一行
_fncSetValue(属性,新的对象[] {例如,tc.ConvertTo(P值,property.PropertyType),空});
}

公共牛逼的GetInstance()
{
返回实例;
}

私有静态Func键< G,对象,对象> SetValueMethod< G>(MethodInfo的pMethod),其中G:类
{
MethodInfo的miGenericHelper = typeof运算(初始化程序< T>)实现getMethod(SetValueMethodHelper,BindingFlags.Static | BindingFlags.NonPublic可);
MethodInfo的miConstructedHelper = miGenericHelper.MakeGenericMethod(typeof运算(G),pMethod.GetParameters()[0] .ParameterType,pMethod.ReturnType);
对象retVal的= miConstructedHelper.Invoke(空,新的对象[] {pMethod});
回报率(Func键< G,对象,对象>)retVal的;
}

私有静态Func键< TTarget,对象,对象> SetValueMethodHelper< TTarget,TParam,TReturn>(MethodInfo的pMethod)其中TTarget:类
{
Func键< TTarget,TParam,TReturn> FUNC =(Func键< TTarget,TParam,TReturn>)Delegate.CreateDelegate(typeof运算(Func键< TTarget,TParam,TReturn>),pMethod);
Func键< TTarget,对象,对象> retVal的=(TTarget目标,对象参数)=> FUNC(目标,(TParam)参数);
返回retVal的;
}
}


解决方案

您使用函数功能在你的代码。 函数功能是有返回类型的方法。对于返回方法无效你需要使用动作



< HR>

您的代码需要看起来像这样:

 公共类实例化< T> ;其中T:新的()
{
私人牛逼实例;
私人的IDictionary<字符串的PropertyInfo>性能;

私人动作<的PropertyInfo,对象,对象,对象> _fncSetValue;

公共实例化()
{$ B $型B型= typeof运算(T);
性能= type.GetProperties()
.GroupBy(P => p.Name)
.ToDictionary(G => g.Key,G => g.ToList() 。第一());

变种类型=新类型[] {typeof运算(对象)的typeof(对象),
的typeof(对象[])};
VAR miSetValue = typeof运算(的PropertyInfo).GetMethod(的SetValue类型);
_fncSetValue = SetValueMethod<&的PropertyInfo GT;(miSetValue);
}

公共无效CreateNewInstance()
{
实例=新T();
}

公共无效的SetValue(字符串pPropertyName,对象P值)
{
如果(pPropertyName == NULL)回报;
的PropertyInfo财产;
如果回报(properties.TryGetValue(pPropertyName,出物业)!);
TypeConverter的TC = TypeDescriptor.GetConverter(property.PropertyType);

VAR值= tc.ConvertTo(P值,property.PropertyType);
_fncSetValue(物业,例如,价值,NULL);
}

公共牛逼的GetInstance()
{
返回实例;
}

私有静态动作< G,对象,对象,对象> SetValueMethod< G>(MethodInfo的pMethod),其中G:类
{
变种miGenericHelper =
的typeof(实例化< T>)实现getMethod(SetValueMethodHelper,
BindingFlags.Static |
BindingFlags.NonPublic可);

VAR参数= pMethod.GetParameters();
VAR miConstructedHelper = miGenericHelper.MakeGenericMethod(typeof运算(G),
参数[0] .ParameterType,
参数[1] .ParameterType,
参数[2] .ParameterType);

VAR retVal的= miConstructedHelper.Invoke(空,新的对象[] {pMethod});
回报率(动作< G,对象,对象,对象>)retVal的;
}

私有静态动作< TTarget,对象,对象,对象> SetValueMethodHelper< TTarget,TParam1,TParam2,TParam3>(MethodInfo的pMethod)其中TTarget:类
{
VAR FUNC =(动作< TTarget,TParam1,TParam2,TParam3>)Delegate.CreateDelegate(typeof运算(动作< TTarget,TParam1,TParam2,TParam3&1+),pMethod);
动作< TTarget,对象,对象,对象> retVal的=
(目标参数1,参数2,参数3)=>
FUNC(目标,(TParam1)参数1,(TParam2)参数2,(TParam3)参数3);

返回retVal的;
}
}






因为你不希望调用像乔恩斯基特任意方法,则可以简化代码的很多的。有一个在你的代码不需要调用 MethodInfo.Invoke 键,因为这是没有必要的代表。你可以简单地调用的SetValue 直接返回的PropertyInfo 。有没有必要使用委托,反过来反正正好调用该方法的弯路。此外,类型转换是不必要的,因为的SetValue 需要对象反正。结果
你的代码可能是这样简单:

 公共类SimpleInstantiator< T>其中T:新的()
{
私人牛逼实例;
私人的IDictionary<字符串的PropertyInfo>性能;

公共SimpleInstantiator()
{$ B $型B型= typeof运算(T);
性能= type.GetProperties()
.GroupBy(P => p.Name)
.ToDictionary(G => g.Key,G => g.ToList() 。第一());
}

公共无效CreateNewInstance()
{
实例=新T();
}

公共无效的SetValue(字符串pPropertyName,对象P值)
{
如果(pPropertyName == NULL)回报;

的PropertyInfo财产;
如果回报(properties.TryGetValue(pPropertyName,出物业)!);

property.SetValue(例如,P值,NULL);
}

公共牛逼的GetInstance()
{
返回实例;
}
}



性能测试结果表明,该版本只需要大约50%结果
在性能上一个微小的增加上一个。是由于这样的事实,我们避免我们的通话链中的两个代表不必要的。然而,绝大多数的速度的提高奠定了在我们去掉了类型转换的事实。


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 return void you need to use Action.


Your code needs to look like this:

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


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 call SetValue directly on the returned PropertyInfo. 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 as SetValue requires an object anyway.
Your code could be as simple as this:

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

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.

这篇关于createDelegate方法,而不是用于思考的SetValue的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆