diff Extensions/JointureAddOn/Emit/FunctionFactory.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Extensions/JointureAddOn/Emit/FunctionFactory.cs	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,323 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace BLToolkit.Emit
+{
+    /// <summary>
+    /// Creates and compiles types instances and methods using expressions, IL code generation
+    /// </summary>
+    /// <remarks>
+    /// Inspired from:
+    /// http://abhi.dcmembers.com/blog/2009/03/25/lambda-based-reflection-vs-normal-reflection-vs-direct-call-4/
+    /// </remarks>
+    public static class FunctionFactory
+    {
+        #region Delegates
+
+        public delegate object GenericGetter(object target);
+
+        public delegate void GenericSetter(object target, object value);
+
+        #endregion
+
+        #region Nested type: Il
+
+        public static class Il
+        {
+            public static object CreateInstance(Type type)
+            {
+                InstantiateObjectHandler instantiateObjectHandler =
+                    DynamicMethodCompiler.CreateInstantiateObjectHandler(type);
+
+                return instantiateObjectHandler();
+            }
+
+            public static T CreateInstance<T>()
+            {
+                return (T) CreateInstance(typeof (T));
+            }
+
+            public static SetHandler CreateSetHandler(Type type, string property)
+            {
+                PropertyInfo propertyInfo = type.GetProperty(property);
+                return CreateSetHandler(type, propertyInfo);
+            }
+
+            public static SetHandler CreateSetHandler(Type type, PropertyInfo propertyInfo)
+            {
+                SetHandler setHandler = DynamicMethodCompiler.CreateSetHandler(type, propertyInfo);
+                return setHandler;
+            }
+
+            public static SetHandler CreateSetHandler<T>(string property)
+            {
+                return CreateSetHandler(typeof (T), property);
+            }
+
+            public static GetHandler CreateGetHandler(Type type, PropertyInfo propertyInfo)
+            {
+                GetHandler getHandler = DynamicMethodCompiler.CreateGetHandler(type, propertyInfo);
+                return getHandler;
+            }
+
+            public static GetHandler CreateGetHandler<T>(PropertyInfo propertyInfo)
+            {
+                return CreateGetHandler(typeof (T), propertyInfo);
+            }
+
+            public static GetHandler CreateGetHandler<T>(string property)
+            {
+                PropertyInfo propertyInfo = typeof (T).GetProperty(property);
+                return CreateGetHandler<T>(propertyInfo);
+            }
+
+            ///
+            /// Creates a dynamic setter for the property
+            ///
+            public static GenericSetter CreateSetMethod(PropertyInfo propertyInfo)
+            {
+                /*
+                * If there's no setter return null
+                */
+                MethodInfo setMethod = propertyInfo.GetSetMethod();
+                if (setMethod == null)
+                    return null;
+
+                /*
+                * Create the dynamic method
+                */
+                var arguments = new Type[2];
+                arguments[0] = arguments[1] = typeof (object);
+
+                var setter = new DynamicMethod(
+                    String.Concat("_Set", propertyInfo.Name, "_"),
+                    typeof (void), arguments, propertyInfo.DeclaringType);
+                ILGenerator generator = setter.GetILGenerator();
+                generator.Emit(OpCodes.Ldarg_0);
+                generator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
+                generator.Emit(OpCodes.Ldarg_1);
+
+                if (propertyInfo.PropertyType.IsClass)
+                    generator.Emit(OpCodes.Castclass, propertyInfo.PropertyType);
+                else
+                    generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
+
+                generator.EmitCall(OpCodes.Callvirt, setMethod, null);
+                generator.Emit(OpCodes.Ret);
+
+                /*
+                * Create the delegate and return it
+                */
+                return (GenericSetter) setter.CreateDelegate(typeof (GenericSetter));
+            }
+
+            ///
+            /// Creates a dynamic getter for the property
+            ///
+            public static GenericGetter CreateGetMethod(PropertyInfo propertyInfo)
+            {
+                /*
+                * If there's no getter return null
+                */
+                MethodInfo getMethod = propertyInfo.GetGetMethod();
+                if (getMethod == null)
+                    return null;
+
+                /*
+                * Create the dynamic method
+                */
+                var arguments = new Type[1];
+                arguments[0] = typeof (object);
+
+                var getter = new DynamicMethod(
+                    String.Concat("_Get", propertyInfo.Name, "_"),
+                    typeof (object), arguments, propertyInfo.DeclaringType);
+
+                ILGenerator generator = getter.GetILGenerator();
+                generator.DeclareLocal(typeof (object));
+                generator.Emit(OpCodes.Ldarg_0);
+                generator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
+                generator.EmitCall(OpCodes.Callvirt, getMethod, null);
+
+                if (!propertyInfo.PropertyType.IsClass)
+                    generator.Emit(OpCodes.Box, propertyInfo.PropertyType);
+
+                generator.Emit(OpCodes.Ret);
+
+                /*
+                * Create the delegate and return it
+                */
+                return (GenericGetter) getter.CreateDelegate(typeof (GenericGetter));
+            }
+        }
+
+        #endregion
+
+        #region Nested type: Lambda
+
+        public static class Lambda
+        {
+            public static T CreateInstance<T>()
+            {
+                return InstanceCreator<T>.CreateInstance();
+            }
+
+            public static List<T> CreateListInstance<T>()
+            {
+                return InstanceCreator<T>.CreateListInstance();
+            }
+
+            public static Action<T, TValue> BuildSet<T, TValue>(string property)
+            {
+                string[] props = property.Split('.');
+                Type type = typeof (T);
+                ParameterExpression arg = Expression.Parameter(type, "x");
+                ParameterExpression valArg = Expression.Parameter(typeof (TValue), "val");
+                Expression expr = arg;
+                foreach (string prop in props.Take(props.Length - 1))
+                {
+                    // use reflection (not ComponentModel) to mirror LINQ 
+                    PropertyInfo pi = type.GetProperty(prop);
+                    expr = Expression.Property(expr, pi);
+                    type = pi.PropertyType;
+                }
+                // final property set...
+                PropertyInfo finalProp = type.GetProperty(props.Last());
+                MethodInfo setter = finalProp.GetSetMethod();
+                expr = Expression.Call(expr, setter, valArg);
+                return Expression.Lambda<Action<T, TValue>>(expr, arg, valArg).Compile();
+            }
+
+            public static Func<T, TValue> BuildGet<T, TValue>(string property)
+            {
+                string[] props = property.Split('.');
+                Type type = typeof (T);
+                ParameterExpression arg = Expression.Parameter(type, "x");
+                Expression expr = arg;
+                foreach (string prop in props)
+                {
+                    // use reflection (not ComponentModel) to mirror LINQ 
+                    PropertyInfo pi = type.GetProperty(prop);
+                    expr = Expression.Property(expr, pi);
+                    type = pi.PropertyType;
+                }
+                return Expression.Lambda<Func<T, TValue>>(expr, arg).Compile();
+            }
+
+            /// <summary>
+            /// Creates a compiled delegate function for the specified type and method name
+            /// </summary>
+            /// <typeparam name="TFunc">Delegate Func to create</typeparam>
+            /// <param name="obj">Constant to get method from</param>
+            /// <param name="methodName">Method to examine</param>
+            /// <returns>Delegate function of the specified methodname</returns>
+            public static TFunc CreateFunc<TFunc>(object obj, string methodName)
+            {
+                var args = new List<ParameterExpression>();
+
+                Type targetType = obj.GetType();
+                MethodInfo minfo = targetType.GetMethod(methodName,
+                                                        BindingFlags.Instance | BindingFlags.Public |
+                                                        BindingFlags.SetProperty);
+
+                if (minfo != null)
+                {
+                    ConstantExpression target = Expression.Constant(obj);
+                    foreach (ParameterInfo arg in minfo.GetParameters())
+                        args.Add(Expression.Parameter(arg.ParameterType, arg.Name));
+                    MethodCallExpression methodinvokeExpression = Expression.Call(target, minfo, args.ToArray());
+                    Expression<TFunc> lambda = Expression.Lambda<TFunc>(methodinvokeExpression, args.ToArray());
+
+                    //now the following Lambda is created:
+                    // (TArg1, TArg2) => obj.MethodName(TArg1, TArg2);
+
+                    return lambda.Compile();
+                }
+                return default(TFunc);
+            }
+
+            /// <summary>
+            /// Creates a compiled delegate function using expressions, 
+            /// the first Func{TObject,TReturn} parameter must be the constant to be passed in
+            /// </summary>
+            /// <typeparam name="TFunc">Delegate Func to create</typeparam>
+            /// <param name="targetType">Type of constant to pass in to the Func</param>
+            /// <param name="methodName">Method to examine</param>
+            /// <returns>Delegate function of the specified methodname</returns>
+            /// <example>
+            /// The function Func{TType,TArg1,TArg2} with a method name of "CallMe" would create the following
+            /// lambda:
+            /// <code>
+            /// (TType, TArg1, TArg2) => TType.CallMe(TArg1, TArg2);
+            /// </code>
+            /// </example>
+            public static TFunc CreateFunc<TFunc>(Type targetType, string methodName)
+            {
+                var args = new List<ParameterExpression>();
+                MethodInfo minfo = targetType.GetMethod(methodName,
+                                                        BindingFlags.Instance | BindingFlags.Public |
+                                                        BindingFlags.SetProperty);
+
+                if (minfo != null)
+                {
+                    Type objectType = typeof (TFunc).GetGenericArguments().First();
+                    ParameterExpression targetParam = Expression.Parameter(objectType, "a");
+
+                    if (!targetType.IsAssignableFrom(objectType))
+                        throw new InvalidCastException(string.Format("{0} cannot be cast to {1}", targetType.Name,
+                                                                     objectType.Name));
+
+                    UnaryExpression target = Expression.Convert(targetParam, targetType);
+                    foreach (ParameterInfo arg in minfo.GetParameters())
+                        args.Add(Expression.Parameter(arg.ParameterType, arg.Name));
+
+                    MethodCallExpression methodinvokeExpression = Expression.Call(target, minfo, args.ToArray());
+                    Expression<TFunc> lambda = Expression.Lambda<TFunc>(methodinvokeExpression,
+                                                                        new[] {targetParam}.Concat(args));
+
+                    //now the following Lambda is created:
+                    // (a, TArg1, TArg2) => a.MethodName(TArg1, TArg2);
+
+                    return lambda.Compile();
+                }
+                return default(TFunc);
+            }
+
+            #region Nested type: InstanceCreator
+
+            private static class InstanceCreator<T>
+            {
+                public static readonly Func<T> CreateInstance =
+                    Expression.Lambda<Func<T>>(Expression.New(typeof (T))).Compile();
+
+                public static readonly Func<List<T>> CreateListInstance =
+                Expression.Lambda<Func<List<T>>>(Expression.New(typeof(List<T>))).Compile();
+            }
+
+            #endregion
+        }
+
+        #endregion
+
+        #region Nested type: Remote
+
+        public static class Remote
+        {
+            public static T CreateInstance<T>()
+            {
+                return Activator.CreateInstance<T>();
+            }
+
+            public  static object CreateInstance(Type type)
+            {
+                return Activator.CreateInstance(type);
+            }
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file