Creating an performant open delegate for an property setter or getter

前端 未结 2 631
滥情空心
滥情空心 2020-12-14 10:01

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

相关标签:
2条回答
  • 2020-12-14 10:39

    I once made this class. Perhaps it helps:

    public class GetterSetter<EntityType,propType>
    {
        private readonly Func<EntityType, propType> getter;
        private readonly Action<EntityType, propType> setter;
        private readonly string propertyName;
        private readonly Expression<Func<EntityType, propType>> propertyNameExpression;
    
        public EntityType Entity { get; set; }
    
        public GetterSetter(EntityType entity, Expression<Func<EntityType, propType>> property_NameExpression)
        {
            Entity = entity;
            propertyName = GetPropertyName(property_NameExpression);
            propertyNameExpression = property_NameExpression;
            //Create Getter
            getter = propertyNameExpression.Compile();
            // Create Setter()
            MethodInfo method = typeof (EntityType).GetProperty(propertyName).GetSetMethod();
            setter = (Action<EntityType, propType>)
                     Delegate.CreateDelegate(typeof(Action<EntityType, propType>), method);
        }
    
    
        public propType Value
        {
            get
            {
                return getter(Entity);
            }
            set
            {
                setter(Entity, value);
            }
        }
    
        protected string GetPropertyName(LambdaExpression _propertyNameExpression)
        {
            var lambda = _propertyNameExpression as LambdaExpression;
            MemberExpression memberExpression;
            if (lambda.Body is UnaryExpression)
            {
                var unaryExpression = lambda.Body as UnaryExpression;
                memberExpression = unaryExpression.Operand as MemberExpression;
            }
            else
            {
                memberExpression = lambda.Body as MemberExpression;
            }
            var propertyInfo = memberExpression.Member as PropertyInfo;
            return propertyInfo.Name;
        }
    

    test:

    var gs = new GetterSetter<OnOffElement,bool>(new OnOffElement(), item => item.IsOn);
            gs.Value = true;
            var result = gs.Value;
    
    0 讨论(0)
  • 2020-12-14 10:41

    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.

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

    Or alternatively with a generic type:

        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;
            }
        }
    
    0 讨论(0)
提交回复
热议问题