Generate dynamic method to set a field of a struct instead of using reflection

前端 未结 6 1169
温柔的废话
温柔的废话 2020-12-08 12:19

Let\'s say I have the following code which update a field of a struct using reflection. Since the struct instance is copied into the DynamicUpdate

6条回答
  •  遥遥无期
    2020-12-08 12:43

    After some experiments:

    public delegate void ClassFieldSetter(T target, TValue value) where T : class;
    
    public delegate void StructFieldSetter(ref T target, TValue value) where T : struct;
    
    public static class FieldSetterCreator
    {
        public static ClassFieldSetter CreateClassFieldSetter(FieldInfo field)
            where T : class
        {
            return CreateSetter>(field);
        }
    
        public static StructFieldSetter CreateStructFieldSetter(FieldInfo field)
            where T : struct
        {
            return CreateSetter>(field);
        }
    
        private static TDelegate CreateSetter(FieldInfo field)
        {
            return (TDelegate)(object)CreateSetter(field, typeof(T), typeof(TValue), typeof(TDelegate));
        }
    
        private static Delegate CreateSetter(FieldInfo field, Type instanceType, Type valueType, Type delegateType)
        {
            if (!field.DeclaringType.IsAssignableFrom(instanceType))
                throw new ArgumentException("The field is declared it different type");
            if (!field.FieldType.IsAssignableFrom(valueType))
                throw new ArgumentException("The field type is not assignable from the value");
    
            var paramType = instanceType.IsValueType ? instanceType.MakeByRefType() : instanceType;
            var setter = new DynamicMethod("", typeof(void),
                                            new[] { paramType, valueType },
                                            field.DeclaringType.Module, true);
    
            var generator = setter.GetILGenerator();
            generator.Emit(OpCodes.Ldarg_0);
            generator.Emit(OpCodes.Ldarg_1);
            generator.Emit(OpCodes.Stfld, field);
            generator.Emit(OpCodes.Ret);
    
            return setter.CreateDelegate(delegateType);
        }
    }
    

    The main difference from the expression tree approach is that readonly fields can also be changed.

提交回复
热议问题