0
|
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 }
|