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 }