Mercurial > pub > bltoolkit
comparison Source/Data/Linq/Builder/ExpressionTestGenerator.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.IO; | |
4 using System.Linq; | |
5 using System.Linq.Expressions; | |
6 using System.Reflection; | |
7 using System.Runtime.CompilerServices; | |
8 using System.Text; | |
9 | |
10 using BLToolkit.Linq; | |
11 | |
12 namespace BLToolkit.Data.Linq.Builder | |
13 { | |
14 class ExpressionTestGenerator | |
15 { | |
16 readonly StringBuilder _exprBuilder = new StringBuilder(); | |
17 | |
18 string _indent = "\t\t\t\t"; | |
19 | |
20 void PushIndent() { _indent += '\t'; } | |
21 void PopIndent () { _indent = _indent.Substring(1); } | |
22 | |
23 readonly HashSet<Expression> _visitedExprs = new HashSet<Expression>(); | |
24 | |
25 bool BuildExpression(Expression expr) | |
26 { | |
27 switch (expr.NodeType) | |
28 { | |
29 case ExpressionType.Add: | |
30 case ExpressionType.AddChecked: | |
31 case ExpressionType.And: | |
32 case ExpressionType.AndAlso: | |
33 #if FW4 || SILVERLIGHT | |
34 case ExpressionType.Assign: | |
35 #endif | |
36 case ExpressionType.Coalesce: | |
37 case ExpressionType.Divide: | |
38 case ExpressionType.Equal: | |
39 case ExpressionType.ExclusiveOr: | |
40 case ExpressionType.GreaterThan: | |
41 case ExpressionType.GreaterThanOrEqual: | |
42 case ExpressionType.LeftShift: | |
43 case ExpressionType.LessThan: | |
44 case ExpressionType.LessThanOrEqual: | |
45 case ExpressionType.Modulo: | |
46 case ExpressionType.Multiply: | |
47 case ExpressionType.MultiplyChecked: | |
48 case ExpressionType.NotEqual: | |
49 case ExpressionType.Or: | |
50 case ExpressionType.OrElse: | |
51 case ExpressionType.Power: | |
52 case ExpressionType.RightShift: | |
53 case ExpressionType.Subtract: | |
54 case ExpressionType.SubtractChecked: | |
55 { | |
56 var e = (BinaryExpression)expr; | |
57 | |
58 _exprBuilder.Append("("); | |
59 | |
60 e.Left.Visit(new Func<Expression,bool>(BuildExpression)); | |
61 | |
62 switch (expr.NodeType) | |
63 { | |
64 case ExpressionType.Add : | |
65 case ExpressionType.AddChecked : _exprBuilder.Append(" + "); break; | |
66 case ExpressionType.And : _exprBuilder.Append(" & "); break; | |
67 case ExpressionType.AndAlso : _exprBuilder.Append(" && "); break; | |
68 #if FW4 || SILVERLIGHT | |
69 case ExpressionType.Assign : _exprBuilder.Append(" = "); break; | |
70 #endif | |
71 case ExpressionType.Coalesce : _exprBuilder.Append(" ?? "); break; | |
72 case ExpressionType.Divide : _exprBuilder.Append(" / "); break; | |
73 case ExpressionType.Equal : _exprBuilder.Append(" == "); break; | |
74 case ExpressionType.ExclusiveOr : _exprBuilder.Append(" ^ "); break; | |
75 case ExpressionType.GreaterThan : _exprBuilder.Append(" > "); break; | |
76 case ExpressionType.GreaterThanOrEqual : _exprBuilder.Append(" >= "); break; | |
77 case ExpressionType.LeftShift : _exprBuilder.Append(" << "); break; | |
78 case ExpressionType.LessThan : _exprBuilder.Append(" < "); break; | |
79 case ExpressionType.LessThanOrEqual : _exprBuilder.Append(" <= "); break; | |
80 case ExpressionType.Modulo : _exprBuilder.Append(" % "); break; | |
81 case ExpressionType.Multiply : | |
82 case ExpressionType.MultiplyChecked : _exprBuilder.Append(" * "); break; | |
83 case ExpressionType.NotEqual : _exprBuilder.Append(" != "); break; | |
84 case ExpressionType.Or : _exprBuilder.Append(" | "); break; | |
85 case ExpressionType.OrElse : _exprBuilder.Append(" || "); break; | |
86 case ExpressionType.Power : _exprBuilder.Append(" ** "); break; | |
87 case ExpressionType.RightShift : _exprBuilder.Append(" >> "); break; | |
88 case ExpressionType.Subtract : | |
89 case ExpressionType.SubtractChecked : _exprBuilder.Append(" - "); break; | |
90 } | |
91 | |
92 e.Right.Visit(new Func<Expression,bool>(BuildExpression)); | |
93 | |
94 _exprBuilder.Append(")"); | |
95 | |
96 return false; | |
97 } | |
98 | |
99 case ExpressionType.ArrayLength: | |
100 { | |
101 var e = (UnaryExpression)expr; | |
102 | |
103 e.Operand.Visit(new Func<Expression,bool>(BuildExpression)); | |
104 _exprBuilder.Append(".Length"); | |
105 | |
106 return false; | |
107 } | |
108 | |
109 case ExpressionType.Convert: | |
110 case ExpressionType.ConvertChecked: | |
111 { | |
112 var e = (UnaryExpression)expr; | |
113 | |
114 _exprBuilder.AppendFormat("({0})", GetTypeName(e.Type)); | |
115 e.Operand.Visit(new Func<Expression,bool>(BuildExpression)); | |
116 | |
117 return false; | |
118 } | |
119 | |
120 case ExpressionType.Negate: | |
121 case ExpressionType.NegateChecked: | |
122 { | |
123 _exprBuilder.Append("-"); | |
124 return true; | |
125 } | |
126 | |
127 case ExpressionType.Not: | |
128 { | |
129 _exprBuilder.Append("!"); | |
130 return true; | |
131 } | |
132 | |
133 case ExpressionType.Quote: | |
134 return true; | |
135 | |
136 case ExpressionType.TypeAs: | |
137 { | |
138 var e = (UnaryExpression)expr; | |
139 | |
140 _exprBuilder.Append("("); | |
141 e.Operand.Visit(new Func<Expression,bool>(BuildExpression)); | |
142 _exprBuilder.AppendFormat(" as {0})", GetTypeName(e.Type)); | |
143 | |
144 return false; | |
145 } | |
146 | |
147 case ExpressionType.UnaryPlus: | |
148 { | |
149 _exprBuilder.Append("+"); | |
150 return true; | |
151 } | |
152 | |
153 case ExpressionType.ArrayIndex: | |
154 { | |
155 var e = (BinaryExpression)expr; | |
156 | |
157 e.Left.Visit(new Func<Expression,bool>(BuildExpression)); | |
158 _exprBuilder.Append("["); | |
159 e.Right.Visit(new Func<Expression,bool>(BuildExpression)); | |
160 _exprBuilder.Append("]"); | |
161 | |
162 return false; | |
163 } | |
164 | |
165 case ExpressionType.MemberAccess : | |
166 { | |
167 var e = (MemberExpression)expr; | |
168 | |
169 e.Expression.Visit(new Func<Expression,bool>(BuildExpression)); | |
170 _exprBuilder.AppendFormat(".{0}", e.Member.Name); | |
171 | |
172 return false; | |
173 } | |
174 | |
175 case ExpressionType.Parameter : | |
176 { | |
177 var e = (ParameterExpression)expr; | |
178 _exprBuilder.Append(e.Name); | |
179 return false; | |
180 } | |
181 | |
182 case ExpressionType.Call : | |
183 { | |
184 var ex = (MethodCallExpression)expr; | |
185 var mi = ex.Method; | |
186 | |
187 var attrs = mi.GetCustomAttributes(typeof(ExtensionAttribute), false); | |
188 | |
189 if (attrs.Length != 0) | |
190 { | |
191 ex.Arguments[0].Visit(new Func<Expression,bool>(BuildExpression)); | |
192 PushIndent(); | |
193 _exprBuilder.AppendLine().Append(_indent); | |
194 } | |
195 else if (ex.Object != null) | |
196 ex.Object.Visit(new Func<Expression,bool>(BuildExpression)); | |
197 else | |
198 _exprBuilder.Append(GetTypeName(mi.DeclaringType)); | |
199 | |
200 _exprBuilder.Append(".").Append(mi.Name); | |
201 | |
202 if (mi.IsGenericMethod && mi.GetGenericArguments().Select(GetTypeName).All(t => t != null)) | |
203 { | |
204 _exprBuilder | |
205 .Append("<") | |
206 .Append(GetTypeNames(mi.GetGenericArguments(), ",")) | |
207 .Append(">"); | |
208 } | |
209 | |
210 _exprBuilder.Append("("); | |
211 | |
212 PushIndent(); | |
213 | |
214 var n = attrs.Length != 0 ? 1 : 0; | |
215 | |
216 for (var i = n; i < ex.Arguments.Count; i++) | |
217 { | |
218 if (i != n) | |
219 _exprBuilder.Append(","); | |
220 | |
221 _exprBuilder.AppendLine().Append(_indent); | |
222 | |
223 ex.Arguments[i].Visit(new Func<Expression,bool>(BuildExpression)); | |
224 } | |
225 | |
226 PopIndent(); | |
227 | |
228 _exprBuilder.Append(")"); | |
229 | |
230 if (attrs.Length != 0) | |
231 { | |
232 PopIndent(); | |
233 } | |
234 | |
235 return false; | |
236 } | |
237 | |
238 case ExpressionType.Constant: | |
239 { | |
240 var c = (ConstantExpression)expr; | |
241 | |
242 if (c.Value is IQueryable) | |
243 { | |
244 var e = ((IQueryable)c.Value).Expression; | |
245 | |
246 if (_visitedExprs.Add(e)) | |
247 { | |
248 e.Visit(new Func<Expression,bool>(BuildExpression)); | |
249 return false; | |
250 } | |
251 } | |
252 | |
253 _exprBuilder.Append(expr); | |
254 | |
255 return true; | |
256 } | |
257 | |
258 case ExpressionType.Lambda: | |
259 { | |
260 var le = (LambdaExpression)expr; | |
261 var ps = le.Parameters | |
262 .Select(p => (GetTypeName(p.Type) + " " + p.Name).TrimStart()) | |
263 .Aggregate("", (p1, p2) => p1 + ", " + p2, p => p.TrimStart(',', ' ')); | |
264 | |
265 _exprBuilder.Append("(").Append(ps).Append(") => "); | |
266 | |
267 le.Body.Visit(new Func<Expression,bool>(BuildExpression)); | |
268 return false; | |
269 } | |
270 | |
271 case ExpressionType.Conditional: | |
272 { | |
273 var e = (ConditionalExpression)expr; | |
274 | |
275 _exprBuilder.Append("("); | |
276 e.Test.Visit(new Func<Expression,bool>(BuildExpression)); | |
277 _exprBuilder.Append(" ? "); | |
278 e.IfTrue.Visit(new Func<Expression,bool>(BuildExpression)); | |
279 _exprBuilder.Append(" : "); | |
280 e.IfFalse.Visit(new Func<Expression,bool>(BuildExpression)); | |
281 _exprBuilder.Append(")"); | |
282 | |
283 return false; | |
284 } | |
285 | |
286 case ExpressionType.New: | |
287 { | |
288 var ne = (NewExpression)expr; | |
289 | |
290 if (IsAnonymous(ne.Type)) | |
291 { | |
292 if (ne.Members.Count == 1) | |
293 { | |
294 _exprBuilder.AppendFormat("new {{ {0} = ", ne.Members[0].Name); | |
295 ne.Arguments[0].Visit(new Func<Expression,bool>(BuildExpression)); | |
296 _exprBuilder.Append(" }}"); | |
297 } | |
298 else | |
299 { | |
300 _exprBuilder.AppendLine("new").Append(_indent).Append("{"); | |
301 | |
302 PushIndent(); | |
303 | |
304 for (var i = 0; i < ne.Members.Count; i++) | |
305 { | |
306 _exprBuilder.AppendLine().Append(_indent).AppendFormat("{0} = ", ne.Members[i].Name); | |
307 ne.Arguments[i].Visit(new Func<Expression,bool>(BuildExpression)); | |
308 | |
309 if (i + 1 < ne.Members.Count) | |
310 _exprBuilder.Append(","); | |
311 } | |
312 | |
313 PopIndent(); | |
314 _exprBuilder.AppendLine().Append(_indent).Append("}"); | |
315 } | |
316 } | |
317 else | |
318 { | |
319 _exprBuilder.AppendFormat("new {0}(", GetTypeName(ne.Type)); | |
320 | |
321 for (var i = 0; i < ne.Arguments.Count; i++) | |
322 { | |
323 ne.Arguments[i].Visit(new Func<Expression,bool>(BuildExpression)); | |
324 if (i + 1 < ne.Arguments.Count) | |
325 _exprBuilder.Append(", "); | |
326 } | |
327 | |
328 _exprBuilder.Append(")"); | |
329 } | |
330 | |
331 return false; | |
332 } | |
333 | |
334 case ExpressionType.MemberInit: | |
335 { | |
336 Func<MemberBinding,bool> modify = b => | |
337 { | |
338 switch (b.BindingType) | |
339 { | |
340 case MemberBindingType.Assignment : | |
341 var ma = (MemberAssignment)b; | |
342 _exprBuilder.AppendFormat("{0} = ", ma.Member.Name); | |
343 ma.Expression.Visit(new Func<Expression,bool>(BuildExpression)); | |
344 break; | |
345 default: | |
346 _exprBuilder.Append(b.ToString()); | |
347 break; | |
348 } | |
349 | |
350 return true; | |
351 }; | |
352 | |
353 var e = (MemberInitExpression)expr; | |
354 | |
355 e.NewExpression.Visit(new Func<Expression,bool>(BuildExpression)); | |
356 | |
357 if (e.Bindings.Count == 1) | |
358 { | |
359 _exprBuilder.Append(" { "); | |
360 modify(e.Bindings[0]); | |
361 _exprBuilder.Append(" }"); | |
362 } | |
363 else | |
364 { | |
365 _exprBuilder.AppendLine().Append(_indent).Append("{"); | |
366 | |
367 PushIndent(); | |
368 | |
369 for (var i = 0; i < e.Bindings.Count; i++) | |
370 { | |
371 _exprBuilder.AppendLine().Append(_indent); | |
372 modify(e.Bindings[i]); | |
373 if (i + 1 < e.Bindings.Count) | |
374 _exprBuilder.Append(","); | |
375 } | |
376 | |
377 PopIndent(); | |
378 _exprBuilder.AppendLine().Append(_indent).Append("}"); | |
379 } | |
380 | |
381 return false; | |
382 } | |
383 | |
384 case ExpressionType.NewArrayInit: | |
385 { | |
386 var e = (NewArrayExpression)expr; | |
387 | |
388 _exprBuilder.AppendFormat("new {0}[]", GetTypeName(e.Type.GetElementType())); | |
389 | |
390 if (e.Expressions.Count == 1) | |
391 { | |
392 _exprBuilder.Append(" { "); | |
393 e.Expressions[0].Visit(new Func<Expression,bool>(BuildExpression)); | |
394 _exprBuilder.Append(" }"); | |
395 } | |
396 else | |
397 { | |
398 _exprBuilder.AppendLine().Append(_indent).Append("{"); | |
399 | |
400 PushIndent(); | |
401 | |
402 for (var i = 0; i < e.Expressions.Count; i++) | |
403 { | |
404 _exprBuilder.AppendLine().Append(_indent); | |
405 e.Expressions[i].Visit(new Func<Expression,bool>(BuildExpression)); | |
406 if (i + 1 < e.Expressions.Count) | |
407 _exprBuilder.Append(","); | |
408 } | |
409 | |
410 PopIndent(); | |
411 _exprBuilder.AppendLine().Append(_indent).Append("}"); | |
412 } | |
413 | |
414 return false; | |
415 } | |
416 | |
417 case ExpressionType.TypeIs: | |
418 { | |
419 var e = (TypeBinaryExpression)expr; | |
420 | |
421 _exprBuilder.Append("("); | |
422 e.Expression.Visit(new Func<Expression, bool>(BuildExpression)); | |
423 _exprBuilder.AppendFormat(" is {0})", e.TypeOperand); | |
424 | |
425 return false; | |
426 } | |
427 | |
428 case ExpressionType.ListInit: | |
429 { | |
430 var e = (ListInitExpression)expr; | |
431 | |
432 e.NewExpression.Visit(new Func<Expression,bool>(BuildExpression)); | |
433 | |
434 if (e.Initializers.Count == 1) | |
435 { | |
436 _exprBuilder.Append(" { "); | |
437 e.Initializers[0].Arguments[0].Visit(new Func<Expression, bool>(BuildExpression)); | |
438 _exprBuilder.Append(" }"); | |
439 } | |
440 else | |
441 { | |
442 _exprBuilder.AppendLine().Append(_indent).Append("{"); | |
443 | |
444 PushIndent(); | |
445 | |
446 for (var i = 0; i < e.Initializers.Count; i++) | |
447 { | |
448 _exprBuilder.AppendLine().Append(_indent); | |
449 e.Initializers[i].Arguments[0].Visit(new Func<Expression,bool>(BuildExpression)); | |
450 if (i + 1 < e.Initializers.Count) | |
451 _exprBuilder.Append(","); | |
452 } | |
453 | |
454 PopIndent(); | |
455 _exprBuilder.AppendLine().Append(_indent).Append("}"); | |
456 } | |
457 | |
458 return false; | |
459 } | |
460 | |
461 case ExpressionType.Invoke: | |
462 { | |
463 var e = (InvocationExpression)expr; | |
464 | |
465 _exprBuilder.Append("Expression.Invoke("); | |
466 e.Expression.Visit(new Func<Expression,bool>(BuildExpression)); | |
467 _exprBuilder.Append(", ("); | |
468 | |
469 for (var i = 0; i < e.Arguments.Count; i++) | |
470 { | |
471 e.Arguments[i].Visit(new Func<Expression,bool>(BuildExpression)); | |
472 if (i + 1 < e.Arguments.Count) | |
473 _exprBuilder.Append(", "); | |
474 } | |
475 _exprBuilder.Append("))"); | |
476 | |
477 return false; | |
478 } | |
479 | |
480 default: | |
481 _exprBuilder.AppendLine("// Unknown expression.").Append(_indent).Append(expr); | |
482 return false; | |
483 } | |
484 } | |
485 | |
486 readonly Dictionary<Type,string> _typeNames = new Dictionary<Type,string> | |
487 { | |
488 { typeof(object), "object" }, | |
489 { typeof(bool), "bool" }, | |
490 { typeof(int), "int" }, | |
491 { typeof(string), "string" }, | |
492 }; | |
493 | |
494 readonly StringBuilder _typeBuilder = new StringBuilder(); | |
495 | |
496 void BuildType(Type type) | |
497 { | |
498 if (type.Namespace != null && type.Namespace.StartsWith("System") || | |
499 IsAnonymous(type) || | |
500 type.Assembly == GetType().Assembly || | |
501 type.IsGenericType && type.GetGenericTypeDefinition() != type) | |
502 return; | |
503 | |
504 var name = type.Name;//.Replace('<', '_').Replace('>', '_').Replace('`', '_').Replace("__f__", ""); | |
505 | |
506 var idx = name.LastIndexOf("`"); | |
507 | |
508 if (idx > 0) | |
509 name = name.Substring(0, idx); | |
510 | |
511 if (type.IsGenericType) | |
512 type = type.GetGenericTypeDefinition(); | |
513 | |
514 var baseClasses = new[] { type.BaseType } | |
515 .Where(t => t != null && t != typeof(object)) | |
516 .Concat(type.GetInterfaces()).ToArray(); | |
517 | |
518 var ctors = type.GetConstructors().Select(c => | |
519 { | |
520 #if SILVERLIGHT | |
521 var attrs = c.GetCustomAttributes(false).ToList(); | |
522 #else | |
523 var attrs = c.GetCustomAttributesData(); | |
524 #endif | |
525 var ps = c.GetParameters().Select(p => GetTypeName(p.ParameterType) + " " + p.Name).ToArray(); | |
526 return string.Format( | |
527 "{0}\n\t\tpublic {1}({2})\n\t\t{{\n\t\t\tthrow new NotImplementedException();\n\t\t}}", | |
528 attrs.Count > 0 ? attrs.Select(a => "\n\t\t" + a.ToString()).Aggregate((a1,a2) => a1 + a2) : "", | |
529 name, | |
530 ps.Length == 0 ? "" : ps.Aggregate((s,t) => s + ", " + t)); | |
531 }).ToList(); | |
532 | |
533 if (ctors.Count == 1 && ctors[0].IndexOf("()") >= 0) | |
534 ctors.Clear(); | |
535 | |
536 var members = type.GetFields().Intersect(_usedMembers.OfType<FieldInfo>()).Select(f => | |
537 { | |
538 #if SILVERLIGHT | |
539 var attrs = f.GetCustomAttributes(false).ToList(); | |
540 #else | |
541 var attrs = f.GetCustomAttributesData(); | |
542 #endif | |
543 return string.Format( | |
544 "{0}\n\t\tpublic {1} {2};", | |
545 attrs.Count > 0 ? attrs.Select(a => "\n\t\t" + a.ToString()).Aggregate((a1,a2) => a1 + a2) : "", | |
546 GetTypeName(f.FieldType), | |
547 f.Name); | |
548 }) | |
549 .Concat( | |
550 type.GetProperties().Intersect(_usedMembers.OfType<PropertyInfo>()).Select(p => | |
551 { | |
552 #if SILVERLIGHT | |
553 var attrs = p.GetCustomAttributes(false).ToList(); | |
554 #else | |
555 var attrs = p.GetCustomAttributesData(); | |
556 #endif | |
557 return string.Format( | |
558 "{0}\n\t\t{3}{1} {2} {{ get; set; }}", | |
559 attrs.Count > 0 ? attrs.Select(a => "\n\t\t" + a.ToString()).Aggregate((a1,a2) => a1 + a2) : "", | |
560 GetTypeName(p.PropertyType), | |
561 p.Name, | |
562 type.IsInterface ? "" : "public "); | |
563 })) | |
564 .Concat( | |
565 type.GetMethods().Intersect(_usedMembers.OfType<MethodInfo>()).Select(m => | |
566 { | |
567 #if SILVERLIGHT | |
568 var attrs = m.GetCustomAttributes(false).ToList(); | |
569 #else | |
570 var attrs = m.GetCustomAttributesData(); | |
571 #endif | |
572 var ps = m.GetParameters().Select(p => GetTypeName(p.ParameterType) + " " + p.Name).ToArray(); | |
573 return string.Format( | |
574 "{0}\n\t\t{5}{4}{1} {2}({3})\n\t\t{{\n\t\t\tthrow new NotImplementedException();\n\t\t}}", | |
575 attrs.Count > 0 ? attrs.Select(a => "\n\t\t" + a.ToString()).Aggregate((a1,a2) => a1 + a2) : "", | |
576 GetTypeName(m.ReturnType), | |
577 m.Name, | |
578 ps.Length == 0 ? "" : ps.Aggregate((s,t) => s + ", " + t), | |
579 m.IsStatic ? "static " : | |
580 m.IsVirtual ? "virtual " : | |
581 m.IsAbstract ? "abstract " : | |
582 "", | |
583 type.IsInterface ? "" : "public "); | |
584 })) | |
585 .ToArray(); | |
586 | |
587 { | |
588 #if SILVERLIGHT | |
589 var attrs = type.GetCustomAttributes(false).ToList(); | |
590 #else | |
591 var attrs = type.GetCustomAttributesData(); | |
592 #endif | |
593 | |
594 _typeBuilder.AppendFormat( | |
595 type.IsGenericType ? | |
596 @" | |
597 namespace {0} | |
598 {{{8} | |
599 {6}{7}{1} {2}<{3}>{5} | |
600 {{{4}{9} | |
601 }} | |
602 }} | |
603 " | |
604 : | |
605 @" | |
606 namespace {0} | |
607 {{{8} | |
608 {6}{7}{1} {2}{5} | |
609 {{{4}{9} | |
610 }} | |
611 }} | |
612 ", | |
613 type.Namespace, | |
614 type.IsInterface ? "interface" : type.IsClass ? "class" : "struct", | |
615 name, | |
616 type.IsGenericType ? GetTypeNames(type.GetGenericArguments(), ",") : null, | |
617 ctors.Count == 0 ? "" : ctors.Aggregate((s,t) => s + "\n" + t), | |
618 baseClasses.Length == 0 ? "" : " : " + GetTypeNames(baseClasses), | |
619 type.IsPublic ? "public " : "", | |
620 type.IsAbstract && !type.IsInterface ? "abstract " : "", | |
621 attrs.Count > 0 ? attrs.Select(a => "\n\t" + a.ToString()).Aggregate((a1,a2) => a1 + a2) : "", | |
622 members.Length > 0 ? | |
623 (ctors.Count != 0 ? "\n" : "") + members.Aggregate((f1,f2) => f1 + "\n" + f2) : | |
624 ""); | |
625 } | |
626 } | |
627 | |
628 string GetTypeNames(IEnumerable<Type> types, string separator = ", ") | |
629 { | |
630 return types.Select(GetTypeName).Aggregate("", (t1,t2) => t1 + separator + t2, p => p.TrimStart(separator.ToCharArray())); | |
631 } | |
632 | |
633 bool IsAnonymous(Type type) | |
634 { | |
635 return type.Name.StartsWith("<>f__AnonymousType"); | |
636 } | |
637 | |
638 string GetTypeName(Type type) | |
639 { | |
640 if (type == null || type == typeof(object)) | |
641 return null; | |
642 | |
643 if (type.IsGenericParameter) | |
644 return type.ToString(); | |
645 | |
646 string name; | |
647 | |
648 if (_typeNames.TryGetValue(type, out name)) | |
649 return name; | |
650 | |
651 if (IsAnonymous(type)) | |
652 { | |
653 _typeNames[type] = null; | |
654 return null; | |
655 } | |
656 | |
657 if (type.IsGenericType) | |
658 { | |
659 var args = type.GetGenericArguments(); | |
660 | |
661 name = ""; | |
662 | |
663 if (type.Namespace != "System") | |
664 name = type.Namespace + "."; | |
665 | |
666 name += type.Name; | |
667 | |
668 var idx = name.LastIndexOf("`"); | |
669 | |
670 if (idx > 0) | |
671 name = name.Substring(0, idx); | |
672 | |
673 if (type.GetGenericTypeDefinition() == typeof(Nullable<>)) | |
674 { | |
675 name = string.Format("{0}?", GetTypeName(args[0])); | |
676 } | |
677 else | |
678 { | |
679 name = string.Format("{0}<{1}>", | |
680 name, | |
681 args.Select(GetTypeName).Aggregate("", (s,t) => s + "," + t, p => p.TrimStart(','))); | |
682 } | |
683 | |
684 _typeNames[type] = name; | |
685 | |
686 return name; | |
687 } | |
688 | |
689 if (type.Namespace == "System") | |
690 return type.Name; | |
691 | |
692 return type.ToString(); | |
693 } | |
694 | |
695 readonly HashSet<MemberInfo> _usedMembers = new HashSet<MemberInfo>(); | |
696 | |
697 void VisitMembers(Expression expr) | |
698 { | |
699 switch (expr.NodeType) | |
700 { | |
701 case ExpressionType.Call : | |
702 { | |
703 var ex = (MethodCallExpression)expr; | |
704 _usedMembers.Add(ex.Method); | |
705 | |
706 if (ex.Method.IsGenericMethod) | |
707 { | |
708 var gmd = ex.Method.GetGenericMethodDefinition(); | |
709 | |
710 if (gmd != ex.Method) | |
711 _usedMembers.Add(gmd); | |
712 | |
713 var ga = ex.Method.GetGenericArguments(); | |
714 | |
715 foreach (var type in ga) | |
716 _usedMembers.Add(type); | |
717 } | |
718 | |
719 break; | |
720 } | |
721 | |
722 case ExpressionType.MemberAccess : | |
723 { | |
724 var ex = (MemberExpression)expr; | |
725 _usedMembers.Add(ex.Member); | |
726 break; | |
727 } | |
728 | |
729 case ExpressionType.MemberInit : | |
730 { | |
731 var ex = (MemberInitExpression)expr; | |
732 | |
733 Action<IEnumerable<MemberBinding>> visit = null; visit = bs => | |
734 { | |
735 foreach (var b in bs) | |
736 { | |
737 _usedMembers.Add(b.Member); | |
738 | |
739 switch (b.BindingType) | |
740 { | |
741 case MemberBindingType.MemberBinding : | |
742 visit(((MemberMemberBinding)b).Bindings); | |
743 break; | |
744 }} | |
745 }; | |
746 | |
747 visit(ex.Bindings); | |
748 break; | |
749 } | |
750 } | |
751 } | |
752 | |
753 readonly HashSet<Type> _usedTypes = new HashSet<Type>(); | |
754 | |
755 void AddType(Type type) | |
756 { | |
757 if (type == null || type == typeof(object) || type.IsGenericParameter || _usedTypes.Contains(type)) | |
758 return; | |
759 | |
760 _usedTypes.Add(type); | |
761 | |
762 if (type.IsGenericType) | |
763 foreach (var arg in type.GetGenericArguments()) | |
764 AddType(arg); | |
765 | |
766 if (type.IsGenericType && type.GetGenericTypeDefinition() != type) | |
767 AddType(type.GetGenericTypeDefinition()); | |
768 | |
769 AddType(type.BaseType); | |
770 | |
771 foreach (var i in type.GetInterfaces()) | |
772 AddType(i); | |
773 } | |
774 | |
775 void VisitTypes(Expression expr) | |
776 { | |
777 AddType(expr.Type); | |
778 | |
779 switch (expr.NodeType) | |
780 { | |
781 case ExpressionType.Call : | |
782 { | |
783 var ex = (MethodCallExpression)expr; | |
784 var mi = ex.Method; | |
785 | |
786 AddType(mi.DeclaringType); | |
787 AddType(mi.ReturnType); | |
788 | |
789 foreach (var arg in mi.GetGenericArguments()) | |
790 AddType(arg); | |
791 | |
792 break; | |
793 } | |
794 } | |
795 } | |
796 | |
797 public string GenerateSource(Expression expr) | |
798 { | |
799 string fileName = null; | |
800 StreamWriter sw = null; | |
801 | |
802 try | |
803 { | |
804 var dir = Path.Combine(Path.GetTempPath(), "bltookit\\"); | |
805 | |
806 if (!Directory.Exists(dir)) | |
807 Directory.CreateDirectory(dir); | |
808 | |
809 var number = 0;//DateTime.Now.Ticks; | |
810 | |
811 fileName = Path.Combine(dir, "ExpressionTest." + number + ".cs"); | |
812 | |
813 expr.Visit(new Action<Expression>(VisitMembers)); | |
814 expr.Visit(new Action<Expression>(VisitTypes)); | |
815 | |
816 foreach (var type in _usedTypes.OrderBy(t => t.Namespace).ThenBy(t => t.Name)) | |
817 BuildType(type); | |
818 | |
819 expr.Visit(new Func<Expression,bool>(BuildExpression)); | |
820 | |
821 _exprBuilder.Replace("<>h__TransparentIdentifier", "tp"); | |
822 | |
823 sw = File.CreateText(fileName); | |
824 | |
825 sw.WriteLine(@"//--------------------------------------------------------------------------------------------------- | |
826 // This code was generated by BLToolkit. | |
827 //--------------------------------------------------------------------------------------------------- | |
828 using System; | |
829 using System.Linq.Expressions; | |
830 | |
831 using NUnit.Framework; | |
832 {0} | |
833 namespace Data.Linq.UserTests | |
834 {{ | |
835 [TestFixture] | |
836 public class UserTest : TestBase | |
837 {{ | |
838 [Test] | |
839 public void Test([DataContexts] string context) | |
840 {{ | |
841 // {1} | |
842 using (var db = GetDataContext(context)) | |
843 {{ | |
844 {2}; | |
845 }} | |
846 }} | |
847 }} | |
848 }} | |
849 ", | |
850 _typeBuilder, | |
851 expr, | |
852 _exprBuilder); | |
853 } | |
854 catch(Exception ex) | |
855 { | |
856 if (sw != null) | |
857 { | |
858 sw.WriteLine(); | |
859 sw.WriteLine(ex.GetType()); | |
860 sw.WriteLine(ex.Message); | |
861 sw.WriteLine(ex.StackTrace); | |
862 } | |
863 } | |
864 finally | |
865 { | |
866 if (sw != null) | |
867 sw.Close(); | |
868 } | |
869 | |
870 return fileName; | |
871 } | |
872 } | |
873 } |