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

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:f990fcb411a9
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Linq.Expressions;
5 using System.Reflection;
6 using System.Reflection.Emit;
7
8 namespace BLToolkit.Emit
9 {
10 /// <summary>
11 /// Creates and compiles types instances and methods using expressions, IL code generation
12 /// </summary>
13 /// <remarks>
14 /// Inspired from:
15 /// http://abhi.dcmembers.com/blog/2009/03/25/lambda-based-reflection-vs-normal-reflection-vs-direct-call-4/
16 /// </remarks>
17 public static class FunctionFactory
18 {
19 #region Delegates
20
21 public delegate object GenericGetter(object target);
22
23 public delegate void GenericSetter(object target, object value);
24
25 #endregion
26
27 #region Nested type: Il
28
29 public static class Il
30 {
31 public static object CreateInstance(Type type)
32 {
33 InstantiateObjectHandler instantiateObjectHandler =
34 DynamicMethodCompiler.CreateInstantiateObjectHandler(type);
35
36 return instantiateObjectHandler();
37 }
38
39 public static T CreateInstance<T>()
40 {
41 return (T) CreateInstance(typeof (T));
42 }
43
44 public static SetHandler CreateSetHandler(Type type, string property)
45 {
46 PropertyInfo propertyInfo = type.GetProperty(property);
47 return CreateSetHandler(type, propertyInfo);
48 }
49
50 public static SetHandler CreateSetHandler(Type type, PropertyInfo propertyInfo)
51 {
52 SetHandler setHandler = DynamicMethodCompiler.CreateSetHandler(type, propertyInfo);
53 return setHandler;
54 }
55
56 public static SetHandler CreateSetHandler<T>(string property)
57 {
58 return CreateSetHandler(typeof (T), property);
59 }
60
61 public static GetHandler CreateGetHandler(Type type, PropertyInfo propertyInfo)
62 {
63 GetHandler getHandler = DynamicMethodCompiler.CreateGetHandler(type, propertyInfo);
64 return getHandler;
65 }
66
67 public static GetHandler CreateGetHandler<T>(PropertyInfo propertyInfo)
68 {
69 return CreateGetHandler(typeof (T), propertyInfo);
70 }
71
72 public static GetHandler CreateGetHandler<T>(string property)
73 {
74 PropertyInfo propertyInfo = typeof (T).GetProperty(property);
75 return CreateGetHandler<T>(propertyInfo);
76 }
77
78 ///
79 /// Creates a dynamic setter for the property
80 ///
81 public static GenericSetter CreateSetMethod(PropertyInfo propertyInfo)
82 {
83 /*
84 * If there's no setter return null
85 */
86 MethodInfo setMethod = propertyInfo.GetSetMethod();
87 if (setMethod == null)
88 return null;
89
90 /*
91 * Create the dynamic method
92 */
93 var arguments = new Type[2];
94 arguments[0] = arguments[1] = typeof (object);
95
96 var setter = new DynamicMethod(
97 String.Concat("_Set", propertyInfo.Name, "_"),
98 typeof (void), arguments, propertyInfo.DeclaringType);
99 ILGenerator generator = setter.GetILGenerator();
100 generator.Emit(OpCodes.Ldarg_0);
101 generator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
102 generator.Emit(OpCodes.Ldarg_1);
103
104 if (propertyInfo.PropertyType.IsClass)
105 generator.Emit(OpCodes.Castclass, propertyInfo.PropertyType);
106 else
107 generator.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
108
109 generator.EmitCall(OpCodes.Callvirt, setMethod, null);
110 generator.Emit(OpCodes.Ret);
111
112 /*
113 * Create the delegate and return it
114 */
115 return (GenericSetter) setter.CreateDelegate(typeof (GenericSetter));
116 }
117
118 ///
119 /// Creates a dynamic getter for the property
120 ///
121 public static GenericGetter CreateGetMethod(PropertyInfo propertyInfo)
122 {
123 /*
124 * If there's no getter return null
125 */
126 MethodInfo getMethod = propertyInfo.GetGetMethod();
127 if (getMethod == null)
128 return null;
129
130 /*
131 * Create the dynamic method
132 */
133 var arguments = new Type[1];
134 arguments[0] = typeof (object);
135
136 var getter = new DynamicMethod(
137 String.Concat("_Get", propertyInfo.Name, "_"),
138 typeof (object), arguments, propertyInfo.DeclaringType);
139
140 ILGenerator generator = getter.GetILGenerator();
141 generator.DeclareLocal(typeof (object));
142 generator.Emit(OpCodes.Ldarg_0);
143 generator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
144 generator.EmitCall(OpCodes.Callvirt, getMethod, null);
145
146 if (!propertyInfo.PropertyType.IsClass)
147 generator.Emit(OpCodes.Box, propertyInfo.PropertyType);
148
149 generator.Emit(OpCodes.Ret);
150
151 /*
152 * Create the delegate and return it
153 */
154 return (GenericGetter) getter.CreateDelegate(typeof (GenericGetter));
155 }
156 }
157
158 #endregion
159
160 #region Nested type: Lambda
161
162 public static class Lambda
163 {
164 public static T CreateInstance<T>()
165 {
166 return InstanceCreator<T>.CreateInstance();
167 }
168
169 public static List<T> CreateListInstance<T>()
170 {
171 return InstanceCreator<T>.CreateListInstance();
172 }
173
174 public static Action<T, TValue> BuildSet<T, TValue>(string property)
175 {
176 string[] props = property.Split('.');
177 Type type = typeof (T);
178 ParameterExpression arg = Expression.Parameter(type, "x");
179 ParameterExpression valArg = Expression.Parameter(typeof (TValue), "val");
180 Expression expr = arg;
181 foreach (string prop in props.Take(props.Length - 1))
182 {
183 // use reflection (not ComponentModel) to mirror LINQ
184 PropertyInfo pi = type.GetProperty(prop);
185 expr = Expression.Property(expr, pi);
186 type = pi.PropertyType;
187 }
188 // final property set...
189 PropertyInfo finalProp = type.GetProperty(props.Last());
190 MethodInfo setter = finalProp.GetSetMethod();
191 expr = Expression.Call(expr, setter, valArg);
192 return Expression.Lambda<Action<T, TValue>>(expr, arg, valArg).Compile();
193 }
194
195 public static Func<T, TValue> BuildGet<T, TValue>(string property)
196 {
197 string[] props = property.Split('.');
198 Type type = typeof (T);
199 ParameterExpression arg = Expression.Parameter(type, "x");
200 Expression expr = arg;
201 foreach (string prop in props)
202 {
203 // use reflection (not ComponentModel) to mirror LINQ
204 PropertyInfo pi = type.GetProperty(prop);
205 expr = Expression.Property(expr, pi);
206 type = pi.PropertyType;
207 }
208 return Expression.Lambda<Func<T, TValue>>(expr, arg).Compile();
209 }
210
211 /// <summary>
212 /// Creates a compiled delegate function for the specified type and method name
213 /// </summary>
214 /// <typeparam name="TFunc">Delegate Func to create</typeparam>
215 /// <param name="obj">Constant to get method from</param>
216 /// <param name="methodName">Method to examine</param>
217 /// <returns>Delegate function of the specified methodname</returns>
218 public static TFunc CreateFunc<TFunc>(object obj, string methodName)
219 {
220 var args = new List<ParameterExpression>();
221
222 Type targetType = obj.GetType();
223 MethodInfo minfo = targetType.GetMethod(methodName,
224 BindingFlags.Instance | BindingFlags.Public |
225 BindingFlags.SetProperty);
226
227 if (minfo != null)
228 {
229 ConstantExpression target = Expression.Constant(obj);
230 foreach (ParameterInfo arg in minfo.GetParameters())
231 args.Add(Expression.Parameter(arg.ParameterType, arg.Name));
232 MethodCallExpression methodinvokeExpression = Expression.Call(target, minfo, args.ToArray());
233 Expression<TFunc> lambda = Expression.Lambda<TFunc>(methodinvokeExpression, args.ToArray());
234
235 //now the following Lambda is created:
236 // (TArg1, TArg2) => obj.MethodName(TArg1, TArg2);
237
238 return lambda.Compile();
239 }
240 return default(TFunc);
241 }
242
243 /// <summary>
244 /// Creates a compiled delegate function using expressions,
245 /// the first Func{TObject,TReturn} parameter must be the constant to be passed in
246 /// </summary>
247 /// <typeparam name="TFunc">Delegate Func to create</typeparam>
248 /// <param name="targetType">Type of constant to pass in to the Func</param>
249 /// <param name="methodName">Method to examine</param>
250 /// <returns>Delegate function of the specified methodname</returns>
251 /// <example>
252 /// The function Func{TType,TArg1,TArg2} with a method name of "CallMe" would create the following
253 /// lambda:
254 /// <code>
255 /// (TType, TArg1, TArg2) => TType.CallMe(TArg1, TArg2);
256 /// </code>
257 /// </example>
258 public static TFunc CreateFunc<TFunc>(Type targetType, string methodName)
259 {
260 var args = new List<ParameterExpression>();
261 MethodInfo minfo = targetType.GetMethod(methodName,
262 BindingFlags.Instance | BindingFlags.Public |
263 BindingFlags.SetProperty);
264
265 if (minfo != null)
266 {
267 Type objectType = typeof (TFunc).GetGenericArguments().First();
268 ParameterExpression targetParam = Expression.Parameter(objectType, "a");
269
270 if (!targetType.IsAssignableFrom(objectType))
271 throw new InvalidCastException(string.Format("{0} cannot be cast to {1}", targetType.Name,
272 objectType.Name));
273
274 UnaryExpression target = Expression.Convert(targetParam, targetType);
275 foreach (ParameterInfo arg in minfo.GetParameters())
276 args.Add(Expression.Parameter(arg.ParameterType, arg.Name));
277
278 MethodCallExpression methodinvokeExpression = Expression.Call(target, minfo, args.ToArray());
279 Expression<TFunc> lambda = Expression.Lambda<TFunc>(methodinvokeExpression,
280 new[] {targetParam}.Concat(args));
281
282 //now the following Lambda is created:
283 // (a, TArg1, TArg2) => a.MethodName(TArg1, TArg2);
284
285 return lambda.Compile();
286 }
287 return default(TFunc);
288 }
289
290 #region Nested type: InstanceCreator
291
292 private static class InstanceCreator<T>
293 {
294 public static readonly Func<T> CreateInstance =
295 Expression.Lambda<Func<T>>(Expression.New(typeof (T))).Compile();
296
297 public static readonly Func<List<T>> CreateListInstance =
298 Expression.Lambda<Func<List<T>>>(Expression.New(typeof(List<T>))).Compile();
299 }
300
301 #endregion
302 }
303
304 #endregion
305
306 #region Nested type: Remote
307
308 public static class Remote
309 {
310 public static T CreateInstance<T>()
311 {
312 return Activator.CreateInstance<T>();
313 }
314
315 public static object CreateInstance(Type type)
316 {
317 return Activator.CreateInstance(type);
318 }
319 }
320
321 #endregion
322 }
323 }