Mercurial > pub > bltoolkit
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 } |