Is there a way to create a delegate to get and set values for a FieldInfo?

后端 未结 8 1980
闹比i
闹比i 2020-12-08 08:18

For properties there are GetGetMethod and GetSetMethod so that I can do:

Getter = (Func)Delegate.CreateDelegate(typeof(         


        
相关标签:
8条回答
  • 2020-12-08 08:56

    As Peter Ritchie suggested, you can compile your own code at runtime. The method will be compiled as soon as you invoke the delegate for the first time. So the first call will be slow, but any subsequent call will be as fast as you can get in .NET without unmanaged pointers/unions. Except for the first call, the delegate is around 500 times faster than FieldInfo directly.

    class DemoProgram
    {
        class Target
        {
            private int value;
        }
    
        static void Main(string[] args)
        {
            FieldInfo valueField = typeof(Target).GetFields(BindingFlags.NonPublic| BindingFlags.Instance).First();
            var getValue = CreateGetter<Target, int>(valueField);
            var setValue = CreateSetter<Target, int>(valueField);
    
            Target target = new Target();
    
            setValue(target, 42);
            Console.WriteLine(getValue(target));
        }
    
        static Func<S, T> CreateGetter<S, T>(FieldInfo field)
        {
            string methodName = field.ReflectedType.FullName + ".get_" + field.Name;
            DynamicMethod setterMethod = new DynamicMethod(methodName, typeof(T), new Type[1] { typeof(S) }, true);
            ILGenerator gen = setterMethod.GetILGenerator();
            if (field.IsStatic)
            {
                gen.Emit(OpCodes.Ldsfld, field);
            }
            else
            {
                gen.Emit(OpCodes.Ldarg_0);
                gen.Emit(OpCodes.Ldfld, field);
            }
            gen.Emit(OpCodes.Ret);
            return (Func<S, T>)setterMethod.CreateDelegate(typeof(Func<S, T>));
        }
    
        static Action<S, T> CreateSetter<S,T>(FieldInfo field)
        {
            string methodName = field.ReflectedType.FullName+".set_"+field.Name;
            DynamicMethod setterMethod = new DynamicMethod(methodName, null, new Type[2]{typeof(S),typeof(T)},true);
            ILGenerator gen = setterMethod.GetILGenerator();
            if (field.IsStatic)
            {
                gen.Emit(OpCodes.Ldarg_1);
                gen.Emit(OpCodes.Stsfld, field);
            }
            else
            {
                gen.Emit(OpCodes.Ldarg_0);
                gen.Emit(OpCodes.Ldarg_1);
                gen.Emit(OpCodes.Stfld, field);
            }
            gen.Emit(OpCodes.Ret);
            return (Action<S, T>)setterMethod.CreateDelegate(typeof(Action<S, T>));
        }
    }
    

    Keep in mind that structs are passed by value. That means an Action<S, T> can not be used to change members of a struct if it is passed by value as the first argument.

    0 讨论(0)
  • 2020-12-08 08:58

    Here is an another option for creating a delegate when you are working with objects (don't know specific type of a field). Though it is slower if field is a structure (because of boxing).

    public static class ReflectionUtility
    {
        public static Func<object, object> CompileGetter(this FieldInfo field)
        {
            string methodName = field.ReflectedType.FullName + ".get_" + field.Name;
            DynamicMethod setterMethod = new DynamicMethod(methodName, typeof(object), new[] { typeof(object) }, true);
            ILGenerator gen = setterMethod.GetILGenerator();
            if (field.IsStatic)
            {
                gen.Emit(OpCodes.Ldsfld, field);
                gen.Emit(field.FieldType.IsClass ? OpCodes.Castclass : OpCodes.Box, field.FieldType);
            }
            else
            {
                gen.Emit(OpCodes.Ldarg_0);
                gen.Emit(OpCodes.Castclass, field.DeclaringType);
                gen.Emit(OpCodes.Ldfld, field);
                gen.Emit(field.FieldType.IsClass ? OpCodes.Castclass : OpCodes.Box, field.FieldType);
            }
            gen.Emit(OpCodes.Ret);
            return (Func<object, object>)setterMethod.CreateDelegate(typeof(Func<object, object>));
        }
    
        public static Action<object, object> CompileSetter(this FieldInfo field)
        {
            string methodName = field.ReflectedType.FullName + ".set_" + field.Name;
            DynamicMethod setterMethod = new DynamicMethod(methodName, null, new[] { typeof(object), typeof(object) }, true);
            ILGenerator gen = setterMethod.GetILGenerator();
            if (field.IsStatic)
            {
                gen.Emit(OpCodes.Ldarg_1);
                gen.Emit(field.FieldType.IsClass ? OpCodes.Castclass : OpCodes.Unbox_Any, field.FieldType);
                gen.Emit(OpCodes.Stsfld, field);
            }
            else
            {
                gen.Emit(OpCodes.Ldarg_0);
                gen.Emit(OpCodes.Castclass, field.DeclaringType);
                gen.Emit(OpCodes.Ldarg_1);
                gen.Emit(field.FieldType.IsClass ? OpCodes.Castclass : OpCodes.Unbox_Any, field.FieldType);
                gen.Emit(OpCodes.Stfld, field);
            }
            gen.Emit(OpCodes.Ret);
            return (Action<object, object>)setterMethod.CreateDelegate(typeof(Action<object, object>));
        }
    }
    
    0 讨论(0)
提交回复
热议问题