Mercurial > pub > bltoolkit
view Extensions/JointureAddOn/Emit/FunctionFactory.cs @ 1:8f65451dc28f
Исправлена проблема с фабрикой и выборкой нескольких объектов в linq выражении
author | cin |
---|---|
date | Fri, 28 Mar 2014 01:04:56 +0400 |
parents | f990fcb411a9 |
children |
line wrap: on
line source
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 } }