comparison Source/Mapping/ExpressionMapper.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;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Linq.Expressions;
6 using System.Reflection;
7
8 using BLToolkit.Common;
9 using BLToolkit.Data.Linq;
10 using BLToolkit.Reflection;
11
12 using JetBrains.Annotations;
13
14 namespace BLToolkit.Mapping
15 {
16 class Mapper<TS,TD>
17 {
18 public Func<TS,MappingContext,TD> Map;
19 }
20
21 class MappingContext
22 {
23 public Dictionary<object,object> Objects;
24 public Func<object,object> GetParent;
25 public List<Action<object>> CrossActions;
26 public Dictionary<object,List<Action<object,object>>> Crosses;
27 }
28
29 class MappingParameters
30 {
31 public MappingSchema MappingSchema;
32 public bool DeepCopy = true;
33 public bool HandleCrossReferences = true;
34 public bool IncludeComplexMapping;
35
36 public Dictionary<object,object> MapperList = new Dictionary<object,object>();
37
38 public bool UseContext;
39 public bool ContextParameterUsed;
40
41 readonly ParameterExpression _mappingContext = Expression.Parameter(typeof(MappingContext), "ctx");
42 public ParameterExpression MappingContext
43 {
44 get
45 {
46 ContextParameterUsed = true;
47 return _mappingContext;
48 }
49 }
50 }
51
52 public class ExpressionMapper<TSource,TDest>
53 {
54 readonly MappingParameters _parameters;
55 private Func<object,object> _getCurrent;
56 private Action<object,object> _setCurrent;
57
58 public bool DeepCopy { get { return _parameters.DeepCopy; } set { _parameters.DeepCopy = value; } }
59 public bool HandleBackReferences { get { return _parameters.HandleCrossReferences; } set { _parameters.HandleCrossReferences = value; } }
60 public bool IncludeComplexMapping { get { return _parameters.IncludeComplexMapping; } set { _parameters.IncludeComplexMapping = value; } }
61
62 public ExpressionMapper()
63 : this(Map.DefaultSchema)
64 {
65 }
66
67 public ExpressionMapper(MappingSchema mappingSchema)
68 {
69 _parameters = new MappingParameters { MappingSchema = mappingSchema };
70 }
71
72 ExpressionMapper(MappingParameters parameters)
73 {
74 _parameters = parameters;
75 }
76
77 #region Value Converter
78
79 interface IValueConvertHelper
80 {
81 Expression GetConverter (Expression source);
82 Expression CheckNull (ExpressionMapper<TSource,TDest> mapper, Expression source, object nullValue, MapValue[] mapValues, object defaultValue, MapValue[] srcMapValues);
83 Expression SourceMapValues(ExpressionMapper<TSource,TDest> mapper, Expression source, object nullValue, object defaultValue, MapValue[] srcMapValues);
84 Expression DestMapValues (ExpressionMapper<TSource,TDest> mapper, Expression source, object nullValue, MapValue[] mapValues, object defaultValue);
85 }
86
87 class ValueConvertHelper<TS,TD> : IValueConvertHelper
88 {
89 public Expression GetConverter(Expression source)
90 {
91 return Expression.Invoke(Expression.Constant(Convert<TD,TS>.From), source);
92 }
93
94 public Expression CheckNull(
95 ExpressionMapper<TSource,TDest> mapper,
96 Expression source,
97 object nullValue,
98 MapValue[] mapValues,
99 object defaultValue,
100 MapValue[] srcMapValues)
101 {
102 var param =
103 source.NodeType != ExpressionType.MemberAccess &&
104 source.NodeType != ExpressionType.Parameter &&
105 source.NodeType != ExpressionType.Constant?
106 Expression.Parameter(typeof(TS), "p") :
107 null;
108
109 var nexpr = Expression.Constant(nullValue ?? default(TD));
110
111 var expr =
112 source.NodeType == ExpressionType.Constant && ((ConstantExpression)source).Value == null ?
113 nexpr as Expression:
114 Expression.Condition(
115 Expression.Equal(param ?? source, Expression.Constant(null)),
116 nexpr.Value == null ? Expression.Convert(nexpr, typeof(TD)) : nexpr as Expression,
117 mapper.GetValueMapper(param ?? source, typeof(TD), false, null, mapValues, defaultValue, srcMapValues));
118
119 return param == null ? expr : Expression.Invoke(Expression.Lambda<Func<TS,TD>>(expr, param), source);
120 }
121
122 public Expression SourceMapValues(
123 ExpressionMapper<TSource,TDest> mapper,
124 Expression source,
125 object nullValue,
126 object defaultValue,
127 MapValue[] srcMapValues)
128 {
129 var param =
130 //source.NodeType != ExpressionType.MemberAccess &&
131 source.NodeType != ExpressionType.Parameter &&
132 source.NodeType != ExpressionType.Constant?
133 Expression.Parameter(typeof(TS), "p") :
134 null;
135
136 var expr = mapper.GetValueMapper(Expression.Constant(defaultValue), typeof(TD), true, nullValue, null, null, null);
137
138 for (var i = srcMapValues.Length - 1; i >= 0; i--)
139 {
140 var value = srcMapValues[i];
141
142 expr = Expression.Condition(
143 Expression.Equal(param ?? source, mapper.GetValueMapper(Expression.Constant(value.OrigValue), typeof(TS), false, null, null, null, null)),
144 mapper.GetValueMapper(Expression.Constant(value.MapValues[0]), typeof(TD), true, nullValue, null, null, null),
145 expr);
146 }
147
148 return param == null ? expr : Expression.Invoke(Expression.Lambda<Func<TS,TD>>(expr, param), source);
149 }
150
151 public Expression DestMapValues(
152 ExpressionMapper<TSource,TDest> mapper,
153 Expression source,
154 object nullValue,
155 MapValue[] mapValues,
156 object defaultValue)
157 {
158 var param =
159 //source.NodeType != ExpressionType.MemberAccess &&
160 source.NodeType != ExpressionType.Parameter &&
161 source.NodeType != ExpressionType.Constant?
162 Expression.Parameter(typeof(TS), "p") :
163 null;
164
165 var expr = mapper.GetValueMapper(Expression.Constant(defaultValue), typeof(TD), true, nullValue, null, null, null);
166
167 for (var i = mapValues.Length - 1; i >= 0; i--)
168 {
169 var value = mapValues[i];
170 var orex = null as Expression;
171
172 foreach (var mapValue in value.MapValues)
173 {
174 var ex = Expression.Equal(param ?? source, mapper.GetValueMapper(Expression.Constant(mapValue), typeof (TS), false, null, null, null, null));
175 orex = orex == null ? ex : Expression.OrElse(orex, ex);
176 }
177
178 if (orex != null)
179 expr = Expression.Condition(
180 orex,
181 mapper.GetValueMapper(Expression.Constant(value.OrigValue), typeof(TD), true, nullValue, null, null, null),
182 expr);
183 }
184
185 return param == null ? expr : Expression.Invoke(Expression.Lambda<Func<TS,TD>>(expr, param), source);
186 }
187 }
188
189 static IValueConvertHelper GetValueHelper(Type stype, Type dtype)
190 {
191 var type = typeof(ValueConvertHelper<,>).MakeGenericType(typeof(TSource), typeof(TDest), stype, dtype);
192 return ((IValueConvertHelper)Activator.CreateInstance(type));
193 }
194
195 #endregion
196
197 #region Object Converter
198
199 interface IConvertHelper
200 {
201 Expression MapObjects(ExpressionMapper<TSource,TDest> mapper, Expression source);
202 Expression MapLists (ExpressionMapper<TSource,TDest> mapper, Expression source);
203 }
204
205 class ConvertHelper<TS,TD> : IConvertHelper
206 where TS : class
207 where TD : class
208 {
209 static TD MapCrossReferences(
210 MappingContext ctx,
211 TS source,
212 Func<TS,TD> func,
213 Func<object,object> getCurrent,
214 Action<object,object> setCurrent)
215 {
216 if (source == null)
217 return null;
218
219 object dest;
220 List<Action<object,object>> list;
221
222 if (ctx.Objects.TryGetValue(source, out dest))
223 {
224 if (dest == null)
225 {
226 if (ctx.Crosses == null)
227 ctx.Crosses = new Dictionary<object,List<Action<object,object>>>();
228
229 if (!ctx.Crosses.TryGetValue(source, out list))
230 ctx.Crosses[source] = list = new List<Action<object,object>>();
231
232 var getParent = ctx.GetParent;
233
234 Action<object,object> setter = (obj,value) => setCurrent(getParent(obj), value);
235
236 list.Add(setter);
237 }
238
239 return (TD)dest;
240 }
241
242 var currParent = ctx.GetParent;
243
244 ctx.GetParent = p => getCurrent(currParent(p));
245 ctx.Objects.Add(source, null);
246 ctx.Objects[source] = dest = func(source);
247 ctx.GetParent = currParent;
248
249 if (ctx.Crosses != null && ctx.Crosses.TryGetValue(source, out list))
250 {
251 if (ctx.CrossActions == null)
252 ctx.CrossActions = new List<Action<object>>();
253
254 foreach (var action in list)
255 {
256 var setValue = action;
257
258 Action<object> f = parent => setValue(parent, dest);
259 ctx.CrossActions.Add(f);
260 }
261
262 ctx.Crosses.Remove(source);
263 }
264
265 return (TD)dest;
266 }
267
268 static TD MapObjects(TS source, Func<TS,TD> func)
269 {
270 return source == null ? null : func(source);
271 }
272
273 public Expression MapObjects(ExpressionMapper<TSource,TDest> mapper, Expression source)
274 {
275 var param = mapper._getCurrent == null ? (ParameterExpression)source : Expression.Parameter(source.Type, "source");
276
277 Expression expr;
278 object m;
279
280 if (mapper._parameters.MapperList.TryGetValue(new { S = typeof(TS), D = typeof(TD) }, out m))
281 {
282 var map = (Mapper<TS,TD>)m;
283
284 if (map.Map == null)
285 {
286 expr = Expression.Invoke(
287 Expression.PropertyOrField(Expression.Constant(map), "Map"),
288 source, mapper._parameters.MappingContext);
289 }
290 else
291 {
292 expr = Expression.Invoke(Expression.Constant(map.Map), source, mapper._parameters.MappingContext);
293 }
294 }
295 else
296 {
297 var exmap = new ExpressionMapper<TS,TD>(mapper._parameters);
298 expr = exmap.GetMemberInit(param);
299 }
300
301 if (mapper._getCurrent == null)
302 return expr;
303
304 if (!mapper.HandleBackReferences)
305 {
306 Expression<Func<object>> func = () => MapObjects((TS)null, null);
307 return Expression.Call((MethodInfo)ReflectionHelper.MemeberInfo(func), source, Expression.Lambda<Func<TS,TD>>(expr, param));
308 }
309 else
310 {
311 mapper._parameters.UseContext = true;
312
313 Expression<Func<object>> func = () => MapCrossReferences(null, null, null, null, null);
314
315 return Expression.Call(
316 (MethodInfo)ReflectionHelper.MemeberInfo(func),
317 mapper._parameters.MappingContext,
318 source,
319 Expression.Lambda<Func<TS,TD>>(expr, param),
320 Expression.Constant(mapper._getCurrent),
321 Expression.Constant(mapper._setCurrent));
322 }
323 }
324
325 interface IItemHelper
326 {
327 Expression MapLists(ExpressionMapper<TSource,TDest> mapper, Expression source);
328 }
329
330 interface IClassItemHelper
331 {
332 MethodInfo GetObjectArrayInfo();
333 MethodInfo GetObjectListInfo(bool isList);
334 }
335
336 class ClassItemHelper<TSourceItem,TDestItem> : IClassItemHelper
337 where TSourceItem : class
338 where TDestItem : class
339 {
340 static TDestItem[] MapObjectArray(MappingContext ctx, IEnumerable<TSourceItem> source, Func<TSourceItem,TDestItem> itemMapper)
341 {
342 if (source == null)
343 return null;
344
345 if (source is ICollection)
346 {
347 var col = (ICollection)source;
348 var dest = new TDestItem[col.Count];
349 var n = 0;
350
351 foreach (var item in source)
352 {
353 var current = n;
354 dest[n++] = ConvertHelper<TSourceItem,TDestItem>.MapCrossReferences(
355 ctx, item, itemMapper,
356 _ => dest[current],
357 (_,v) => { dest[current] = (TDestItem)v; });
358 }
359
360 return dest;
361 }
362 else
363 {
364 TDestItem[] dest = null;
365
366 var list = new List<TDestItem>();
367 var n = 0;
368
369 foreach (var item in source)
370 {
371 var current = n;
372 list.Add(null);
373 list[n++] = ConvertHelper<TSourceItem,TDestItem>.MapCrossReferences(
374 ctx, item, itemMapper,
375 _ => dest == null ? list[current] : dest[current],
376 (_,v) => { if (dest == null) list[current] = (TDestItem)v; else dest[current] = (TDestItem)v; });
377 }
378
379 return dest = list.ToArray();
380 }
381 }
382
383 [UsedImplicitly]
384 static TList MapObjectList<TList>(MappingContext ctx, IEnumerable<TSourceItem> source, Func<TSourceItem,TDestItem> itemMapper)
385 where TList : class, IList<TDestItem>, new()
386 {
387 if (source == null)
388 return null;
389
390 var n = 0;
391 var dest = source is ICollection && typeof(TList) == typeof(List<TDestItem>) ?
392 (TList)(IList<TDestItem>)new List<TDestItem>(((ICollection)source).Count) : new TList();
393
394 foreach (var item in source)
395 {
396 var current = n;
397 dest.Add(null);
398 dest[n++] = ConvertHelper<TSourceItem,TDestItem>.MapCrossReferences(
399 ctx, item, itemMapper,
400 _ => dest[current],
401 (_,v) => { dest[current] = (TDestItem)v; });
402 }
403
404 return dest;
405 }
406
407 public MethodInfo GetObjectArrayInfo()
408 {
409 Expression<Func<object>> arrMapper = () => MapObjectArray(null, null, null);
410 return (MethodInfo)ReflectionHelper.MemeberInfo(arrMapper);
411 }
412
413 public MethodInfo GetObjectListInfo(bool isList)
414 {
415 var method = typeof(ClassItemHelper<TSourceItem,TDestItem>).GetMethod("MapObjectList", BindingFlags.NonPublic | BindingFlags.Static);
416 return method.MakeGenericMethod(isList ? typeof (List<TDestItem>) : typeof (TD));
417 }
418 }
419
420 class ItemHelper<TSourceItem,TDestItem> : IItemHelper
421 {
422 static TDestItem[] MapScalarArray(IEnumerable<TSourceItem> source, Func<TSourceItem,TDestItem> itemMapper)
423 {
424 if (source == null)
425 return null;
426
427 if (source is ICollection)
428 {
429 var col = (ICollection)source;
430 var dest = new TDestItem[col.Count];
431 var n = 0;
432
433 foreach (var item in source)
434 dest[n++] = itemMapper(item);
435
436 return dest;
437 }
438
439 return source.Select(itemMapper).ToArray();
440 }
441
442 [UsedImplicitly]
443 static TList MapScalarList<TList>(IEnumerable<TSourceItem> source, Func<TSourceItem,TDestItem> itemMapper)
444 where TList : class, IList<TDestItem>, new()
445 {
446 if (source == null)
447 return null;
448
449 var dest = new TList();
450 var list = dest as List<TDestItem>;
451
452 if (list != null)
453 list.AddRange(source.Select(itemMapper));
454 else
455 foreach (var item in source)
456 dest.Add(itemMapper(item));
457
458 return dest;
459 }
460
461 public Expression MapLists(ExpressionMapper<TSource,TDest> mapper, Expression source)
462 {
463 var itemMapper =
464 new ExpressionMapper<TSourceItem,TDestItem>(mapper._parameters);
465
466 var itemParam = Expression.Parameter(typeof(TSourceItem), "item");
467 var itemExpr = itemMapper.GetValueMapper(
468 itemParam,
469 typeof(TDestItem),
470 true,
471 mapper._parameters.MappingSchema.GetNullValue (typeof(TDestItem)),
472 mapper._parameters.MappingSchema.GetMapValues (typeof(TDestItem)),
473 mapper._parameters.MappingSchema.GetDefaultValue(typeof(TDestItem)),
474 mapper._parameters.MappingSchema.GetMapValues (typeof(TSourceItem)));
475
476 var itemLambda = Expression.Lambda<Func<TSourceItem,TDestItem>>(itemExpr, itemParam);
477
478 var isSourceScalar = !typeof(TSourceItem).IsArray && TypeHelper.IsScalar(typeof(TSourceItem));
479 var isDestScalar = !typeof(TDestItem). IsArray && TypeHelper.IsScalar(typeof(TDestItem));
480
481 if (!mapper.HandleBackReferences || isSourceScalar || isDestScalar)
482 {
483 if (typeof (TD).IsArray)
484 {
485 Expression<Func<object>> arrMapper = () => MapScalarArray(null, null);
486 return Expression.Call((MethodInfo)ReflectionHelper.MemeberInfo(arrMapper), source, itemLambda);
487 }
488
489 var isList =
490 typeof (TD) == typeof (IEnumerable<TDestItem>) || typeof (TD) == typeof (ICollection<TDestItem>) ||
491 typeof (TD) == typeof (IList<TDestItem>) || typeof (TD) == typeof (List<TDestItem>);
492
493 var method = typeof (ItemHelper<TSourceItem, TDestItem>).GetMethod("MapScalarList", BindingFlags.NonPublic | BindingFlags.Static);
494
495 method = method.MakeGenericMethod(isList ? typeof (List<TDestItem>) : typeof (TD));
496
497 return Expression.Call(method, source, itemLambda);
498 }
499 else
500 {
501 mapper._parameters.UseContext = true;
502
503 var type = typeof (ClassItemHelper<,>).MakeGenericType(
504 typeof (TSource), typeof (TDest),
505 typeof (TS), typeof (TD),
506 typeof (TSourceItem), typeof (TDestItem));
507
508 var helper = ((IClassItemHelper)Activator.CreateInstance(type));
509
510 if (typeof (TD).IsArray)
511 return Expression.Call(helper.GetObjectArrayInfo(), mapper._parameters.MappingContext, source, itemLambda);
512
513 var isList =
514 typeof (TD) == typeof (IEnumerable<TDestItem>) || typeof (TD) == typeof (ICollection<TDestItem>) ||
515 typeof (TD) == typeof (IList<TDestItem>) || typeof (TD) == typeof (List<TDestItem>);
516
517 return Expression.Call(helper.GetObjectListInfo(isList), mapper._parameters.MappingContext, source, itemLambda);
518 }
519 }
520 }
521
522 public Expression MapLists(ExpressionMapper<TSource,TDest> mapper, Expression source)
523 {
524 var ts = TypeHelper.GetGenericType(typeof(IEnumerable<>), typeof(TS)).GetGenericArguments()[0];
525 var td = TypeHelper.GetGenericType(typeof(IEnumerable<>), typeof(TD)).GetGenericArguments()[0];
526
527 var type = typeof(ItemHelper<,>).MakeGenericType(typeof(TSource), typeof(TDest), typeof(TS), typeof(TD), ts, td);
528 return ((IItemHelper)Activator.CreateInstance(type)).MapLists(mapper, source);
529 }
530 }
531
532 static IConvertHelper GetHelper(Type stype, Type dtype)
533 {
534 var type = typeof(ConvertHelper<,>).MakeGenericType(typeof(TSource), typeof(TDest), stype, dtype);
535 return ((IConvertHelper)Activator.CreateInstance(type));
536 }
537
538 #endregion
539
540 Expression GetValueMapper(
541 Expression source,
542 Type dtype,
543 bool checkNull,
544 object nullValue,
545 MapValue[] destMapValues,
546 object defaultValue,
547 MapValue[] srcMapValues)
548 {
549 var stype = source.Type;
550
551 var isSourceScalar = !stype.IsArray && TypeHelper.IsScalar(stype);
552 var isDestScalar = !dtype.IsArray && TypeHelper.IsScalar(dtype);
553
554 if (dtype == typeof(object) || dtype == stype && (!DeepCopy || isSourceScalar))
555 return source;
556
557 var isSourceNullable = TypeHelper.IsNullableType(stype) || stype.IsClass;
558
559 if (checkNull && isSourceNullable && !TypeHelper.IsNullableType(dtype) && (isDestScalar || isSourceScalar))
560 return GetValueHelper(stype, dtype).CheckNull(this, source, nullValue, destMapValues, defaultValue, srcMapValues);
561
562 if (srcMapValues != null)
563 return GetValueHelper(stype, dtype).SourceMapValues(this, source, nullValue, defaultValue, srcMapValues);
564
565 if (destMapValues != null)
566 return GetValueHelper(stype, dtype).DestMapValues(this, source, nullValue, destMapValues, defaultValue);
567
568 if (dtype == typeof (string))
569 return
570 isSourceNullable
571 ?
572 Expression.Condition(
573 Expression.Equal(source, Expression.Constant(null)),
574 Expression.Constant(null),
575 Expression.Call(source, "ToString", Array<Type>.Empty)) as Expression
576 :
577 Expression.Call(source, "ToString", Array<Type>.Empty);
578
579 if (!isDestScalar && !isSourceScalar)
580 {
581 if (TypeHelper.GetGenericType(typeof(IEnumerable<>), dtype) != null &&
582 TypeHelper.GetGenericType(typeof(IEnumerable<>), stype) != null)
583 return GetHelper(stype, dtype).MapLists(this, source);
584
585 return GetHelper(stype, dtype).MapObjects(this, source);
586 }
587
588 try
589 {
590 return Expression.Convert(source, dtype);
591 }
592 catch (InvalidOperationException)
593 {
594 }
595
596 return GetValueHelper(stype, dtype).GetConverter(source);
597 }
598
599 IEnumerable<MemberBinding> GetBindings(Expression source)
600 {
601 var dest = _parameters.MappingSchema.GetObjectMapper(typeof(TDest));
602 var src = _parameters.MappingSchema.GetObjectMapper(typeof(TSource));
603
604 foreach (MemberMapper dmm in dest)
605 {
606 if (!IncludeComplexMapping && dmm is MemberMapper.ComplexMapper)
607 continue;
608
609 var dma = dmm.MemberAccessor;
610
611 if (!dma.HasSetter)
612 continue;
613
614 var attr = dma.GetAttribute<ExpressionMapIgnoreAttribute>();
615
616 if (attr != null && attr.Ignore)
617 continue;
618
619 var smm = src[dmm.Name];
620
621 if (smm == null)
622 continue;
623
624 if (!IncludeComplexMapping && smm is MemberMapper.ComplexMapper)
625 continue;
626
627 var sma = smm.MemberAccessor;
628
629 if (!sma.HasGetter)
630 continue;
631
632 attr = sma.GetAttribute<ExpressionMapIgnoreAttribute>();
633
634 if (attr != null && attr.Ignore)
635 continue;
636
637 _getCurrent = dma.GetValue;
638 _setCurrent = dma.SetValue;
639
640 var bind = Expression.Bind(
641 dma.MemberInfo,
642 GetValueMapper(
643 Expression.PropertyOrField(source, sma.Name),
644 dma.Type,
645 true,
646 dmm.MapMemberInfo.NullValue,
647 dmm.MapMemberInfo.MapValues,
648 dmm.MapMemberInfo.DefaultValue,
649 smm.MapMemberInfo.MapValues));
650
651 yield return bind;
652 }
653
654 var destMembers = from m in ((IEnumerable<MemberAccessor>)dest.TypeAccessor) select m;
655
656 destMembers = destMembers.Except(dest.Select(mm => mm.MemberAccessor)).ToList();
657
658 var srcMembers =
659 (from m in ((IEnumerable<MemberAccessor>)src.TypeAccessor) select m)
660 .Except(src.Select(mm => mm.MemberAccessor))
661 .ToList();
662
663 foreach (var dma in destMembers)
664 {
665 if (!dma.HasSetter)
666 continue;
667
668 var sma = srcMembers.FirstOrDefault(mi => mi.Name == dma.Name);
669
670 if (sma == null || !sma.HasGetter)
671 continue;
672
673 _getCurrent = dma.GetValue;
674 _setCurrent = dma.SetValue;
675
676 var bind = Expression.Bind(
677 dma.MemberInfo,
678 GetValueMapper(
679 Expression.MakeMemberAccess(source, sma.MemberInfo),
680 dma.Type,
681 true,
682 _parameters.MappingSchema.GetNullValue (dma.Type),
683 _parameters.MappingSchema.GetMapValues (dma.Type),
684 _parameters.MappingSchema.GetDefaultValue(dma.Type),
685 _parameters.MappingSchema.GetMapValues (sma.Type)));
686
687 yield return bind;
688 }
689 }
690
691 Expression GetMemberInit(ParameterExpression source)
692 {
693 var mapper = new Mapper<TSource,TDest>();
694
695 _parameters.MapperList.Add(new { S = typeof(TSource), D = typeof(TDest) }, mapper);
696
697 var dest = TypeAccessor<TDest>.Instance;
698 var expr = Expression.MemberInit(Expression.New(dest.Type), GetBindings(source));
699
700 mapper.Map = Expression.Lambda<Func<TSource,MappingContext,TDest>>(expr, source, _parameters.MappingContext).Compile();
701
702 return expr;
703 }
704
705 interface IAbstractHelper
706 {
707 Func<TSource,TDest> GetMapper(MappingParameters ps);
708 }
709
710 class AbstractHelper<TS,TD> : IAbstractHelper
711 {
712 public Func<TSource,TDest> GetMapper(MappingParameters ps)
713 {
714 var em = new ExpressionMapper<TS,TD>(ps);
715 var mapper = em.GetMapper();
716
717 return source => (TDest)(object)mapper((TS)(object)source);
718 }
719 }
720
721 public Func<TSource,TDest> GetMapper()
722 {
723 if (typeof(TSource) == typeof(TDest) && !DeepCopy)
724 return s => (TDest)(object)s;
725
726 if (TypeHelper.IsAbstractClass(typeof(TSource)) || TypeHelper.IsAbstractClass(typeof(TDest)))
727 {
728 var st = TypeHelper.IsAbstractClass(typeof(TSource)) ? TypeAccessor<TSource>.Instance.Type : typeof(TSource);
729 var dt = TypeHelper.IsAbstractClass(typeof(TDest)) ? TypeAccessor<TDest>. Instance.Type : typeof(TDest);
730
731 var type = typeof(AbstractHelper<,>).MakeGenericType(typeof(TSource), typeof(TDest), st, dt);
732 return ((IAbstractHelper)Activator.CreateInstance(type)).GetMapper(_parameters);
733 }
734
735 var parm = Expression.Parameter(typeof(TSource), "src");
736 var expr = GetValueMapper(
737 parm,
738 typeof(TDest),
739 true,
740 _parameters.MappingSchema.GetNullValue (typeof(TDest)),
741 _parameters.MappingSchema.GetMapValues (typeof(TDest)),
742 _parameters.MappingSchema.GetDefaultValue(typeof(TDest)),
743 _parameters.MappingSchema.GetMapValues (typeof(TSource)));
744
745 if (_parameters.ContextParameterUsed)
746 {
747 var l = Expression.Lambda<Func<TSource,MappingContext,TDest>>(expr, parm, _parameters.MappingContext);
748 var f = l.Compile();
749
750 if (!_parameters.UseContext)
751 return s => f(s, null);
752
753 return s =>
754 {
755 var ctx = new MappingContext
756 {
757 Objects = new Dictionary<object,object>(10) { { s, null } },
758 GetParent = p => p,
759 };
760
761 var dest = f(s, ctx);
762
763 if (ctx.CrossActions != null)
764 foreach (var circle in ctx.CrossActions)
765 circle(dest);
766
767 if (ctx.Crosses != null)
768 {
769 List<Action<object,object>> list;
770
771 if (ctx.Crosses.TryGetValue(s, out list))
772 foreach (var action in list)
773 action(dest, dest);
774 }
775
776 return dest;
777 };
778 }
779
780 var lambda = Expression.Lambda<Func<TSource,TDest>>(expr, parm);
781
782 return lambda.Compile();
783 }
784 }
785 }