为属性设置器或getter创建一个性能开放的委托 [英] Creating an performant open delegate for an property setter or getter

查看:128
本文介绍了为属性设置器或getter创建一个性能开放的委托的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一个开放委托是一个没有目标的实例方法的委托。要调用它,您将提供目标作为其第一个参数。它们是一种聪明的方法来优化代码,否则将使用反射并且性能较差。有关开放代表的介绍,请参阅这个。您在实践中使用它的方式是使用昂贵的反思代码来构建这些开放的代表,但是您可以以简单的代理呼叫的方式很便宜地调用它们。

An open delegate is a delegate to an instance method without the target. To call it you supply the target as its first parameter. They are a clever way to optimize code that otherwise would use reflection and have poor performance. For an intro to open delegates see this. The way you would use it in practice is to have expensive reflection code to build these open delegates, but then you would be able to call them very cheaply as a simple Delegate call.

我正在尝试编写一个将一个任意PropertyInfo转换成这样一个委托的代码。到目前为止,我想出了这一点:

I'm trying to write code that will transform an arbitrary PropertyInfo, into such an delegate for its setter. So far I came up with this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Test
{
    class TestClass
    {
        static Action<T, object> MakeSetterDelegate<T>(PropertyInfo property)
        {
            MethodInfo setMethod = property.GetSetMethod();
            if (setMethod != null && setMethod.GetParameters().Length == 1) //skips over nasty index properties
            {
                //To be able to bind to the delegate we have to create a delegate 
                //type like: Action<T,actualType> rather than Action<T,object>.
                //We use reflection to do that
                Type setterGenericType = typeof(Action<,>);
                Type delegateType = setterGenericType.MakeGenericType(new Type[] { typeof(T), property.PropertyType });
                var untypedDelegate = Delegate.CreateDelegate(delegateType, setMethod);

                //we wrap the Action<T,actualType> delegate into an Action<T,object>
                Action<T, object> setter = (instance, value) =>
                {
                    untypedDelegate.DynamicInvoke(new object[] { instance, value });
                };
                return setter;
            }
            else
            {
                return null;
            }
        }

        int TestProp 
        {
            set
            {
                System.Diagnostics.Debug.WriteLine("Called set_TestProp");
            }
        }

        static void Test() 
        {
            PropertyInfo property = typeof(TestClass).GetProperty("TestProp");
            Action<TestClass, object> setter = MakeSetterDelegate<TestClass>(property);
            TestClass instance = new TestClass();
            setter(instance, 5);
        }
    }
}

类似的代码将为吸气剂。它有效,但是setter委托使用DynamicInvoke从Action < derivedType >转换为Action < object >,我怀疑是吃了我以后的优化的很大一部分。所以问题是:

Similar code would be written for the getter. It works, but the setter delegate uses a DynamicInvoke to convert from an Action<derivedType> to Action<object>, which I suspect is eating a good part of the optimization I'm after. So the questions are:


  1. DynamicInvoke是真正的问题吗?

  2. 有没有?


推荐答案

DynamicInvoke 做一个表演者。反对通用内部类型的反映是您在这里更好的选择,因为这将允许您使用键入的代理。另一个选项是 DynamicMethod ,但是您需要担心几个IL细节。

DynamicInvoke will not make a performant setter. Reflection against a generic inner type is your better option here, as this will allow you to use typed delegates. Another option is DynamicMethod, but then you need to worry about a few IL details.

可能想查看 HyperDescriptor ,它将IL工作包装到一个 PropertyDescriptor 实现中。另一个选项是 Expression API(如果您使用的是.NET 3.5或更高版本):

You might want to look at HyperDescriptor, which wraps up the IL work into a PropertyDescriptor implementation. Another option is the Expression API (if you are using .NET 3.5 or above):

static Action<T, object> MakeSetterDelegate<T>(PropertyInfo property)
{
    MethodInfo setMethod = property.GetSetMethod();
    if (setMethod != null && setMethod.GetParameters().Length == 1)
    {
        var target = Expression.Parameter(typeof(T));
        var value = Expression.Parameter(typeof(object));
        var body = Expression.Call(target, setMethod,
            Expression.Convert(value, property.PropertyType));
        return Expression.Lambda<Action<T, object>>(body, target, value)
            .Compile();
    }
    else
    {
        return null;
    }
}

或者使用通用类型:

    abstract class Setter<T>
    {
        public abstract void Set(T obj, object value);
    }
    class Setter<TTarget, TValue> : Setter<TTarget>
    {
        private readonly Action<TTarget, TValue> del;
        public Setter(MethodInfo method)
        {
            del = (Action<TTarget, TValue>)
                Delegate.CreateDelegate(typeof(Action<TTarget, TValue>), method);
        }
        public override void Set(TTarget obj, object value)
        {
            del(obj, (TValue)value);
        }

    }
    static Action<T, object> MakeSetterDelegate<T>(PropertyInfo property)
    {
        MethodInfo setMethod = property.GetSetMethod();
        if (setMethod != null && setMethod.GetParameters().Length == 1)
        {
            Setter<T> untyped = (Setter<T>) Activator.CreateInstance(
                typeof(Setter<,>).MakeGenericType(typeof(T),
                property.PropertyType), setMethod);
            return untyped.Set;
        }
        else
        {
            return null;
        }
    }

这篇关于为属性设置器或getter创建一个性能开放的委托的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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