简体   繁体   English

使用反射动态创建类的getter和setter的C#动态委托

[英]C# Dynamic delegate for getter and setter of dynamically created class using reflection

I am using this .Net reflection code to generate a dynamic class instance at runtime. 我正在使用此.Net反射代码在运行时生成动态类实例。

https://www.c-sharpcorner.com/UploadFile/87b416/dynamically-create-a-class-at-runtime/ https://www.c-sharpcorner.com/UploadFile/87b416/dynamically-create-a-class-at-runtime/

I am using .Net reflections to create list of objects with dynamic set of properties since I am reading input from excel file which may have dynamic columns as per the business requirement. 我正在使用.Net反射来创建具有动态属性集的对象列表,因为我从excel文件读取了输入,根据业务需求,该文件可能具有动态列。 But I am doing lot of loops to get the GetType().GetProperty("") which is reducing the performance. 但是我正在做很多循环来获取GetType().GetProperty("") ,这会降低性能。 I am trying to delegate it dynamically for the PropertiesInfo[] which I get from the GetType().GetProperties() . 我试图将它动态地委托给从GetType().GetProperties()获得的PropertiesInfo[]

Below is a static getter and setter delegate for Property1 of the runtime class created. 下面是创建的运行时类的Property1的静态getter和setter委托。

Action<MyClass, int> setter = (Action<MyClass, int>)Delegate.CreateDelegate(typeof(Action<MyClass, int>), null, typeof(MyClass).GetProperty("Property1").GetSetMethod());  

Func<MyClass, int> getter = (Func<MyClass, int>)Delegate.CreateDelegate(typeof(Func<MyClass, int>), null, typeof(MyClass).GetProperty("Property1").GetGetMethod());

I would like to make this dynamic for each property created of my class. 我想使我的班级创建的每个属性动态。 I'm stuck and not sure whether I can use any Linq MemberExpression to achieve it. 我很MemberExpression ,不确定是否可以使用任何Linq MemberExpression来实现它。

Can anyone help me out? 谁能帮我吗? That would be great. 那很好啊。

Here's a rather basic solution to your problem, simply caching away Getters/Setters per Type. 这是一个解决您问题的基本方法,只需缓存每种类型的Getters / Setters。

public static class CachedPropertyAccessUtilsFactory
{
    /*
     * Convenience Factory to avoid creating instances of
     * CachedPropertyAccessUtils by reflection
     */
    public static CachedPropertyAccessUtils<TWrapped> Create<TWrapped>(
        TWrapped instance)
    {
        return new CachedPropertyAccessUtils<TWrapped>(instance);
    }
}

public class CachedPropertyAccessUtils<TWrapped>
{
    private readonly TWrapped _instance;

    public CachedPropertyAccessUtils(TWrapped instance)
    {
        _instance = instance;
    }

    public GetSetWrapper<TProperty> Property<TProperty>(string propertyName)
    {
        return new GetSetWrapper<TProperty>(_instance, propertyName);
    }

    public class GetSetWrapper<TProperty>
    {
        /*
         * Caches generated getters/setters by property name.
         * Since this field is static it is shared between all instances with
         * identical TWrapped and TProperty.
         */
        private static readonly ConcurrentDictionary<string, GetterAndSetterTuple> GettersAndSettersByPropertyName
            = new ConcurrentDictionary<string, GetterAndSetterTuple>();

        private readonly TWrapped _instance;
        private readonly string _propertyName;

        public GetSetWrapper(TWrapped instance, string propertyName)
        {
            _instance = instance;
            _propertyName = propertyName;

            // Create a Getter/Setter pair if none has been generated previously
            GettersAndSettersByPropertyName.GetOrAdd(propertyName, _ => new GetterAndSetterTuple() {
                Getter = (Func<TWrapped, TProperty>)Delegate
                    .CreateDelegate(typeof(Func<TWrapped, TProperty>),
                        null,
                        typeof(TWrapped)
                            .GetProperty(propertyName)
                            .GetGetMethod()),
                Setter = (Action<TWrapped, TProperty>)Delegate
                    .CreateDelegate(typeof(Action<TWrapped, TProperty>),
                        null,
                        typeof(TWrapped)
                            .GetProperty(propertyName)
                            .GetSetMethod())
            });
        }

        public TProperty GetValue()
        {
            return GettersAndSettersByPropertyName[_propertyName].Getter(_instance);
        }

        public GetSetWrapper<TProperty> SetValue(TProperty value)
        {
            GettersAndSettersByPropertyName[_propertyName].Setter(_instance, value);
            return this;
        }

        class GetterAndSetterTuple
        {
            public Func  <TWrapped, TProperty> Getter { get; set; }
            public Action<TWrapped, TProperty> Setter { get; set; }
        }
    }
}

Example usage: 用法示例:

var myInstance = SomeCodeToCreateATypeAtRuntimeAndCreateAnInstanceOfIt();

var wrappedInstance = CachedPropertyAccessUtilsFactory.Create(myInstance);

// The first call to Property() will generate the corresponding Getter/Setter
wrappedInstance.Property<int>("Property1").SetValue(99);

// Subsequent calls will use the cached Getter/Setter
wrappedInstance.Property<int>("Property1").GetValue(); // => 99

// The property can be conveniently held on to:
var property1 = wrappedInstance.Property<int>("Property1");

property1.SetValue(-1);
property1.GetValue(); // => -1

All this of course assumes you know the property types at runtime so you can switch into the right Property<TProperty>() call. 所有这些当然都假定您在运行时知道属性类型,因此可以switch到正确的Property<TProperty>()调用。

If you don't have this information, another layer of indirection could be added, mapping string propertyName to the respective property on the wrapped type by reflection and caching the lookup result. 如果您没有此信息,则可以添加另一层间接层,通过反射将string propertyName映射到包装类型上的相应属性并缓存查找结果。
In this case, the returned GetSetWrapper would of course have to support GetValue / SetValue with object as the return/argument type which would involve a bit of casting/boxing back and forth behind the scenes. 在这种情况下,返回的GetSetWrapper当然必须支持以object为返回/参数类型的GetValue / SetValue ,这将需要在幕后进行一些投射/装箱。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM