动态方法的实际例子?

发布于 2024-08-16 05:34:17 字数 65 浏览 7 评论 0原文

我想学习动态方法及其使用 C# 的实际示例。
动态方法和Reflection有什么关系吗?
请帮我。

I want to learn dynamic method and its practical example using c#.
Is there any relation between dynamic method and Reflection?
Please help me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

凡尘雨 2024-08-23 05:34:17

我们正在使用动态方法来加速反射。
这是我们的反射优化器的代码。它只比直接调用慢 10%,而反射调用

public class ReflectionEmitPropertyAccessor
    {
        private readonly bool canRead;
        private readonly bool canWrite;
        private IPropertyAccessor emittedPropertyAccessor;
        private readonly string propertyName;
        private readonly Type propertyType;
        private readonly Type targetType;
        private Dictionary<Type,OpCode> typeOpCodes;

        public ReflectionEmitPropertyAccessor(Type targetType, string property)
        {
            this.targetType = targetType;
            propertyName = property;
            var propertyInfo = targetType.GetProperty(property);
            if (propertyInfo == null)
            {
                throw new ReflectionOptimizerException(string.Format("Property \"{0}\" is not found in type "+ "{1}.", property, targetType));
            }
            canRead = propertyInfo.CanRead;
            canWrite = propertyInfo.CanWrite;
            propertyType = propertyInfo.PropertyType;
        }

        public bool CanRead
        {
            get { return canRead; }
        }

        public bool CanWrite
        {
            get { return canWrite; }
        }

        public Type TargetType
        {
            get { return targetType; }
        }

        public Type PropertyType
        {
            get { return propertyType; }
        }

        #region IPropertyAccessor Members

        public object Get(object target)
        {
            if (canRead)
            {
                if (emittedPropertyAccessor == null)
                {
                    Init();
                }

                if (emittedPropertyAccessor != null) return emittedPropertyAccessor.Get(target);

            }
            else
            {
                throw new ReflectionOptimizerException(string.Format("У свойства \"{0}\" нет метода get.", propertyName));
            }
            throw new ReflectionOptimizerException("Fail initialize of " + GetType().FullName);
        }

        public void Set(object target, object value)
        {
            if (canWrite)
            {
                if (emittedPropertyAccessor == null)
                {
                    Init();
                }
                if (emittedPropertyAccessor != null) emittedPropertyAccessor.Set(target, value);
            }
            else
            {
                throw new ReflectionOptimizerException(string.Format("Property \"{0}\" does not have method set.", propertyName));
            }
            throw new ReflectionOptimizerException("Fail initialize of " + GetType().FullName);
        }

        #endregion

        private void Init()
        {
            InitTypeOpCodes();
            var assembly = EmitAssembly();
            emittedPropertyAccessor = assembly.CreateInstance("Property") as IPropertyAccessor;
            if (emittedPropertyAccessor == null)
            {
                throw new ReflectionOptimizerException("Shit happense in PropertyAccessor.");
            }
        }

        private void InitTypeOpCodes()
        {
            typeOpCodes = new Dictionary<Type, OpCode>
                            {
                                {typeof (sbyte), OpCodes.Ldind_I1},
                                {typeof (byte), OpCodes.Ldind_U1},
                                {typeof (char), OpCodes.Ldind_U2},
                                {typeof (short), OpCodes.Ldind_I2},
                                {typeof (ushort), OpCodes.Ldind_U2},
                                {typeof (int), OpCodes.Ldind_I4},
                                {typeof (uint), OpCodes.Ldind_U4},
                                {typeof (long), OpCodes.Ldind_I8},
                                {typeof (ulong), OpCodes.Ldind_I8},
                                {typeof (bool), OpCodes.Ldind_I1},
                                {typeof (double), OpCodes.Ldind_R8},
                                {typeof (float), OpCodes.Ldind_R4}
                            };
        }

        private Assembly EmitAssembly()
        {
            var assemblyName = new AssemblyName {Name = "PropertyAccessorAssembly"};
            var newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
            var newModule = newAssembly.DefineDynamicModule("Module");
            var dynamicType = newModule.DefineType("Property", TypeAttributes.Public);
            dynamicType.AddInterfaceImplementation(typeof(IPropertyAccessor));
            dynamicType.DefineDefaultConstructor(MethodAttributes.Public);
            var getParamTypes = new[] { typeof(object) };
            var getReturnType = typeof(object);
            var getMethod = dynamicType.DefineMethod("Get",
                                    MethodAttributes.Public | MethodAttributes.Virtual,
                                    getReturnType,
                                    getParamTypes);

            var getIL = getMethod.GetILGenerator();
            var targetGetMethod = targetType.GetMethod("get_" + propertyName);

            if (targetGetMethod != null)
            {
                getIL.DeclareLocal(typeof(object));
                getIL.Emit(OpCodes.Ldarg_1); //Load the first argument 
                getIL.Emit(OpCodes.Castclass, targetType); //Cast to the source type
                getIL.EmitCall(OpCodes.Call, targetGetMethod, null); //Get the property value
                if (targetGetMethod.ReturnType.IsValueType)
                {
                    getIL.Emit(OpCodes.Box, targetGetMethod.ReturnType); //Box
                }
                getIL.Emit(OpCodes.Stloc_0); //Store it
                getIL.Emit(OpCodes.Ldloc_0);
            }
            else
            {
                getIL.ThrowException(typeof(MissingMethodException));
            }

            getIL.Emit(OpCodes.Ret);
            var setParamTypes = new[] { typeof(object), typeof(object) };
            const Type setReturnType = null;
            var setMethod = dynamicType.DefineMethod("Set",
                                    MethodAttributes.Public | MethodAttributes.Virtual,
                                    setReturnType,
                                    setParamTypes);

            var setIL = setMethod.GetILGenerator();

            var targetSetMethod = targetType.GetMethod("set_" + propertyName);
            if (targetSetMethod != null)
            {
                Type paramType = targetSetMethod.GetParameters()[0].ParameterType;

                setIL.DeclareLocal(paramType);
                setIL.Emit(OpCodes.Ldarg_1); //Load the first argument //(target object)
                setIL.Emit(OpCodes.Castclass, targetType); //Cast to the source type
                setIL.Emit(OpCodes.Ldarg_2); //Load the second argument 
                //(value object)
                if (paramType.IsValueType)
                {
                    setIL.Emit(OpCodes.Unbox, paramType); //Unbox it    
                    if (typeOpCodes.ContainsKey(paramType)) //and load
                    {
                        var load = typeOpCodes[paramType];
                        setIL.Emit(load);
                    }
                    else
                    {
                        setIL.Emit(OpCodes.Ldobj, paramType);
                    }
                }
                else
                {
                    setIL.Emit(OpCodes.Castclass, paramType); //Cast class
                }
                setIL.EmitCall(OpCodes.Callvirt,targetSetMethod, null); //Set the property value
            }
            else
            {
                setIL.ThrowException(typeof(MissingMethodException));
            }
            setIL.Emit(OpCodes.Ret);
            // Load the type
            dynamicType.CreateType();
            return newAssembly;
        }

    }

实现是从不同来源聚合的,速度快 2000 倍,主要是这篇 CodeProject 文章。

We are using Dynamic methods for speed up Reflection.
Here is code of our reflection optimizer. it is only 10% slower than direct call and 2000 times faster that reflection call

public class ReflectionEmitPropertyAccessor
    {
        private readonly bool canRead;
        private readonly bool canWrite;
        private IPropertyAccessor emittedPropertyAccessor;
        private readonly string propertyName;
        private readonly Type propertyType;
        private readonly Type targetType;
        private Dictionary<Type,OpCode> typeOpCodes;

        public ReflectionEmitPropertyAccessor(Type targetType, string property)
        {
            this.targetType = targetType;
            propertyName = property;
            var propertyInfo = targetType.GetProperty(property);
            if (propertyInfo == null)
            {
                throw new ReflectionOptimizerException(string.Format("Property \"{0}\" is not found in type "+ "{1}.", property, targetType));
            }
            canRead = propertyInfo.CanRead;
            canWrite = propertyInfo.CanWrite;
            propertyType = propertyInfo.PropertyType;
        }

        public bool CanRead
        {
            get { return canRead; }
        }

        public bool CanWrite
        {
            get { return canWrite; }
        }

        public Type TargetType
        {
            get { return targetType; }
        }

        public Type PropertyType
        {
            get { return propertyType; }
        }

        #region IPropertyAccessor Members

        public object Get(object target)
        {
            if (canRead)
            {
                if (emittedPropertyAccessor == null)
                {
                    Init();
                }

                if (emittedPropertyAccessor != null) return emittedPropertyAccessor.Get(target);

            }
            else
            {
                throw new ReflectionOptimizerException(string.Format("У свойства \"{0}\" нет метода get.", propertyName));
            }
            throw new ReflectionOptimizerException("Fail initialize of " + GetType().FullName);
        }

        public void Set(object target, object value)
        {
            if (canWrite)
            {
                if (emittedPropertyAccessor == null)
                {
                    Init();
                }
                if (emittedPropertyAccessor != null) emittedPropertyAccessor.Set(target, value);
            }
            else
            {
                throw new ReflectionOptimizerException(string.Format("Property \"{0}\" does not have method set.", propertyName));
            }
            throw new ReflectionOptimizerException("Fail initialize of " + GetType().FullName);
        }

        #endregion

        private void Init()
        {
            InitTypeOpCodes();
            var assembly = EmitAssembly();
            emittedPropertyAccessor = assembly.CreateInstance("Property") as IPropertyAccessor;
            if (emittedPropertyAccessor == null)
            {
                throw new ReflectionOptimizerException("Shit happense in PropertyAccessor.");
            }
        }

        private void InitTypeOpCodes()
        {
            typeOpCodes = new Dictionary<Type, OpCode>
                            {
                                {typeof (sbyte), OpCodes.Ldind_I1},
                                {typeof (byte), OpCodes.Ldind_U1},
                                {typeof (char), OpCodes.Ldind_U2},
                                {typeof (short), OpCodes.Ldind_I2},
                                {typeof (ushort), OpCodes.Ldind_U2},
                                {typeof (int), OpCodes.Ldind_I4},
                                {typeof (uint), OpCodes.Ldind_U4},
                                {typeof (long), OpCodes.Ldind_I8},
                                {typeof (ulong), OpCodes.Ldind_I8},
                                {typeof (bool), OpCodes.Ldind_I1},
                                {typeof (double), OpCodes.Ldind_R8},
                                {typeof (float), OpCodes.Ldind_R4}
                            };
        }

        private Assembly EmitAssembly()
        {
            var assemblyName = new AssemblyName {Name = "PropertyAccessorAssembly"};
            var newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
            var newModule = newAssembly.DefineDynamicModule("Module");
            var dynamicType = newModule.DefineType("Property", TypeAttributes.Public);
            dynamicType.AddInterfaceImplementation(typeof(IPropertyAccessor));
            dynamicType.DefineDefaultConstructor(MethodAttributes.Public);
            var getParamTypes = new[] { typeof(object) };
            var getReturnType = typeof(object);
            var getMethod = dynamicType.DefineMethod("Get",
                                    MethodAttributes.Public | MethodAttributes.Virtual,
                                    getReturnType,
                                    getParamTypes);

            var getIL = getMethod.GetILGenerator();
            var targetGetMethod = targetType.GetMethod("get_" + propertyName);

            if (targetGetMethod != null)
            {
                getIL.DeclareLocal(typeof(object));
                getIL.Emit(OpCodes.Ldarg_1); //Load the first argument 
                getIL.Emit(OpCodes.Castclass, targetType); //Cast to the source type
                getIL.EmitCall(OpCodes.Call, targetGetMethod, null); //Get the property value
                if (targetGetMethod.ReturnType.IsValueType)
                {
                    getIL.Emit(OpCodes.Box, targetGetMethod.ReturnType); //Box
                }
                getIL.Emit(OpCodes.Stloc_0); //Store it
                getIL.Emit(OpCodes.Ldloc_0);
            }
            else
            {
                getIL.ThrowException(typeof(MissingMethodException));
            }

            getIL.Emit(OpCodes.Ret);
            var setParamTypes = new[] { typeof(object), typeof(object) };
            const Type setReturnType = null;
            var setMethod = dynamicType.DefineMethod("Set",
                                    MethodAttributes.Public | MethodAttributes.Virtual,
                                    setReturnType,
                                    setParamTypes);

            var setIL = setMethod.GetILGenerator();

            var targetSetMethod = targetType.GetMethod("set_" + propertyName);
            if (targetSetMethod != null)
            {
                Type paramType = targetSetMethod.GetParameters()[0].ParameterType;

                setIL.DeclareLocal(paramType);
                setIL.Emit(OpCodes.Ldarg_1); //Load the first argument //(target object)
                setIL.Emit(OpCodes.Castclass, targetType); //Cast to the source type
                setIL.Emit(OpCodes.Ldarg_2); //Load the second argument 
                //(value object)
                if (paramType.IsValueType)
                {
                    setIL.Emit(OpCodes.Unbox, paramType); //Unbox it    
                    if (typeOpCodes.ContainsKey(paramType)) //and load
                    {
                        var load = typeOpCodes[paramType];
                        setIL.Emit(load);
                    }
                    else
                    {
                        setIL.Emit(OpCodes.Ldobj, paramType);
                    }
                }
                else
                {
                    setIL.Emit(OpCodes.Castclass, paramType); //Cast class
                }
                setIL.EmitCall(OpCodes.Callvirt,targetSetMethod, null); //Set the property value
            }
            else
            {
                setIL.ThrowException(typeof(MissingMethodException));
            }
            setIL.Emit(OpCodes.Ret);
            // Load the type
            dynamicType.CreateType();
            return newAssembly;
        }

    }

implementation is aggregated from different sources and main is this CodeProject article.

耳根太软 2024-08-23 05:34:17

您可以通过 DynamicMethod 类创建方法。

DynamicMethod squareIt = new DynamicMethod(
    "SquareIt", 
    typeof(long), 
    methodArgs, 
    typeof(Example).Module);

ILGenerator il = squareIt.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Conv_I8);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Mul);
il.Emit(OpCodes.Ret);

MSDN 上完整评论的示例
需要注意的是,使用这种方法的开发速度非常慢,而且用处不大。

You can create a method via DynamicMethod class.

DynamicMethod squareIt = new DynamicMethod(
    "SquareIt", 
    typeof(long), 
    methodArgs, 
    typeof(Example).Module);

ILGenerator il = squareIt.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Conv_I8);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Mul);
il.Emit(OpCodes.Ret);

Fully commented example on MSDN
I should note that the development using this method is very slow and not very useful.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文