MapperConfigurationBase.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. using Masuit.Tools.Mapping.Exceptions;
  2. using Masuit.Tools.Mapping.Helper;
  3. using Masuit.Tools.Mapping.Visitor;
  4. using System;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using System.Collections.ObjectModel;
  8. using System.Linq;
  9. using System.Linq.Expressions;
  10. using System.Reflection;
  11. namespace Masuit.Tools.Mapping.Core
  12. {
  13. /// <summary>
  14. /// mapper配置基类
  15. /// </summary>
  16. public abstract class MapperConfigurationBase
  17. {
  18. private Delegate _delegateCallForNew;
  19. private Delegate _delegateCallForExisting;
  20. private Func<Type, object> _constructorFunc;
  21. private bool _isInitialized;
  22. private readonly MethodInfo _selectMethod;
  23. private readonly MethodInfo _toListMethod;
  24. private readonly List<PropertyInfo> _propertiesToIgnore;
  25. internal ParameterExpression paramClassSource;
  26. internal MapperExpressionVisitor visitorMapper;
  27. internal List<MemberAssignment> memberForNew;
  28. internal LambdaExpression expressionForExisting;
  29. /// <summary>
  30. /// 属性映射对应关系<br/>
  31. /// Item1 : 源表达式<br/>
  32. /// Item2 : 目标表达式<br/>
  33. /// Item3 : 检查null值<br/>
  34. /// Item4 : mapper别名<br/>
  35. /// </summary>
  36. protected List<Tuple<Expression, Expression, bool, string>> PropertiesMapping { get; private set; }
  37. /// <summary>
  38. /// 需要被忽略映射的属性
  39. /// </summary>
  40. protected ReadOnlyCollection<PropertyInfo> PropertiesToIgnore => _propertiesToIgnore.AsReadOnly();
  41. /// <summary>
  42. /// 是否使用服务依赖注入
  43. /// </summary>
  44. public bool UseServiceLocator { get; protected set; }
  45. /// <summary>
  46. /// 对象源类型
  47. /// </summary>
  48. public Type SourceType { get; }
  49. /// <summary>
  50. /// 对象目标类型
  51. /// </summary>
  52. public Type TargetType { get; }
  53. /// <summary>
  54. /// 获取mapper映射成员
  55. /// </summary>
  56. public ReadOnlyCollection<MemberAssignment> MemberToMapForNew => new ReadOnlyCollection<MemberAssignment>(memberForNew);
  57. /// <summary>
  58. /// mapper别名
  59. /// </summary>
  60. public string Name { get; protected set; }
  61. /// <summary>
  62. /// 构造函数
  63. /// </summary>
  64. /// <param name="source">源类型</param>
  65. /// <param name="destination">目标类型</param>
  66. /// <param name="paramName">属性名</param>
  67. /// <param name="name">别名</param>
  68. protected MapperConfigurationBase(Type source, Type destination, string paramName, string name = null)
  69. {
  70. TargetType = destination;
  71. SourceType = source;
  72. paramClassSource = Expression.Parameter(source, paramName);
  73. Name = string.IsNullOrEmpty(name) ? paramName : name;
  74. _propertiesToIgnore = new List<PropertyInfo>();
  75. PropertiesMapping = new List<Tuple<Expression, Expression, bool, string>>();
  76. visitorMapper = new MapperExpressionVisitor(paramClassSource);
  77. memberForNew = new List<MemberAssignment>();
  78. _selectMethod = typeof(Enumerable).GetMethods().Where(m => m.Name == "Select").Select(x => x.GetParameters().First(p => p.Name.Equals("selector") && p.ParameterType.GetGenericArguments().Length == 2)).First().Member as MethodInfo;
  79. _toListMethod = typeof(Enumerable).GetMethod("ToList");
  80. }
  81. /// <summary>
  82. /// 获取mapper委托
  83. /// </summary>
  84. /// <returns></returns>
  85. public Delegate GetDelegate()
  86. {
  87. if (!_isInitialized)
  88. {
  89. throw new MapperNotInitializedException(SourceType, TargetType);
  90. }
  91. // 因为在这里有映射器的性能问题,而缓存委托会显着缩短处理时间,如果没有表达式编译每次编译会很慢
  92. return _delegateCallForNew ??= Expression.Lambda(GetMemberInitExpression(), paramClassSource).Compile();
  93. }
  94. /// <summary>
  95. /// 获取现有目标类型的委托。
  96. /// </summary>
  97. /// <exception cref="MapperNotInitializedException"></exception>
  98. public Delegate GetDelegateForExistingTarget()
  99. {
  100. if (!_isInitialized)
  101. {
  102. throw new MapperNotInitializedException(SourceType, TargetType);
  103. }
  104. // 因为在这里有映射器的性能问题,而缓存委托会显着缩短处理时间,如果没有表达式编译每次编译会很慢
  105. if (_delegateCallForExisting == null)
  106. {
  107. CreateMemberAssignementForExistingTarget();
  108. }
  109. return _delegateCallForExisting;
  110. }
  111. /// <summary>
  112. /// 获取泛型的Lambda表达式
  113. /// </summary>
  114. public LambdaExpression GetGenericLambdaExpression()
  115. {
  116. return Expression.Lambda(GetMemberInitExpression(), paramClassSource);
  117. }
  118. /// <summary>
  119. /// 获取目标类型的实际类型
  120. /// </summary>
  121. public Type GetDestinationType()
  122. {
  123. return GetRealType(TargetType);
  124. }
  125. /// <summary>
  126. /// 忽略目标类型的属性
  127. /// </summary>
  128. /// <typeparam name="TDest">对象源类型</typeparam>
  129. /// <typeparam name="TProperty">对象目标类型</typeparam>
  130. /// <param name="propertyDest">目标对象的属性</param>
  131. /// <returns></returns>
  132. protected MapperConfigurationBase IgnoreBase<TDest, TProperty>(Expression<Func<TDest, TProperty>> propertyDest)
  133. {
  134. // 添加到映射列表并且可以继续操作
  135. _propertiesToIgnore.Add(GetPropertyInfo(propertyDest));
  136. return this;
  137. }
  138. /// <summary>
  139. /// 获取映射器实例
  140. /// </summary>
  141. /// <param name="typeOfSource">源类型</param>
  142. /// <param name="typeOfTarget">目标类型</param>
  143. /// <param name="throwExceptionOnNoFound">如果没找到是否需要抛出异常</param>
  144. /// <param name="name">mapper别名</param>
  145. /// <returns></returns>
  146. /// <exception cref="NoFoundMapperException"></exception>
  147. protected static MapperConfigurationBase GetMapper(Type typeOfSource, Type typeOfTarget, bool throwExceptionOnNoFound, string name = null)
  148. {
  149. var mapperExterne = MapperConfigurationCollectionContainer.Instance.Find(typeOfSource, typeOfTarget, name);
  150. // 如果没有任何配置,手动抛出异常
  151. if (mapperExterne == null && throwExceptionOnNoFound)
  152. {
  153. throw new NoFoundMapperException(typeOfSource, typeOfTarget);
  154. }
  155. return mapperExterne;
  156. }
  157. /// <summary>
  158. /// 创建公共成员
  159. /// </summary>
  160. protected void CreateCommonMember()
  161. {
  162. PropertyInfo[] propertiesSource = SourceType.GetProperties();
  163. foreach (PropertyInfo propSource in propertiesSource)
  164. {
  165. PropertyInfo propDest = TargetType.GetProperty(propSource.Name);
  166. if (propDest != null)
  167. {
  168. // 检查是否已存在或被忽略。
  169. bool ignorePropDest = _propertiesToIgnore.Exists(x => x.Name == propDest.Name) || PropertiesMapping.Exists(x => GetPropertyInfo(x.Item2).Name == propDest.Name);
  170. if (propDest.CanWrite && !ignorePropDest)
  171. {
  172. Type sourceType = propSource.PropertyType;
  173. Type destType = propDest.PropertyType;
  174. bool isList = IsListOf(destType);
  175. if (isList)
  176. {
  177. sourceType = TypeSystem.GetElementType(propSource.PropertyType);
  178. destType = TypeSystem.GetElementType(propDest.PropertyType);
  179. }
  180. var canCreateConfig = CanCreateConfig(sourceType, destType);
  181. if (canCreateConfig.CanCreate)
  182. {
  183. // 只创造现有的关系
  184. Expression expSource = Expression.MakeMemberAccess(paramClassSource, propSource);
  185. ParameterExpression paramDest = Expression.Parameter(TargetType, "t");
  186. Expression expDest = Expression.MakeMemberAccess(paramDest, propDest);
  187. PropertiesMapping.Add(Tuple.Create(expSource, expDest, false, canCreateConfig.MapperName));
  188. }
  189. }
  190. }
  191. }
  192. }
  193. private static CreateConfig CanCreateConfig(Type typeSource, Type typeTarget)
  194. {
  195. var result = new CreateConfig
  196. {
  197. CanCreate = typeSource == typeTarget
  198. };
  199. //不是同一类型
  200. if (!result.CanCreate)
  201. {
  202. //查找是否存在映射器
  203. var mapper = MapperConfigurationCollectionContainer.Instance.Find(typeSource, typeTarget);
  204. if (mapper != null)
  205. {
  206. result.MapperName = mapper.Name;
  207. result.CanCreate = true;
  208. }
  209. }
  210. return result;
  211. }
  212. /// <summary>
  213. /// 检查并配置mapper
  214. /// </summary>
  215. /// <param name="configExpression">配置表达式树</param>
  216. /// <exception cref="NotSameTypePropertyException">
  217. /// </exception>
  218. /// <exception cref="ReadOnlyPropertyException"></exception>
  219. protected void CheckAndConfigureMapping(ref Tuple<Expression, Expression, bool, string> configExpression)
  220. {
  221. Type typeSource = configExpression.Item1.Type;
  222. Type typeTarget = configExpression.Item2.Type;
  223. // 正常情况下,目标表达式是一个成员表达式树
  224. var propTarget = GetPropertyInfo(configExpression.Item2);
  225. if (propTarget.CanWrite)
  226. {
  227. CheckAndRemoveMemberDest(propTarget.Name);
  228. if (!IsListOf(typeTarget))
  229. {
  230. CreatBindingFromSimple(ref configExpression, typeSource, typeTarget, propTarget);
  231. }
  232. else
  233. {
  234. CreateBindingFromList(ref configExpression, typeSource, typeTarget, propTarget);
  235. }
  236. }
  237. else
  238. {
  239. throw new ReadOnlyPropertyException(propTarget);
  240. }
  241. }
  242. /// <summary>
  243. /// 检查并移除目标成员
  244. /// </summary>
  245. /// <param name="properyName">属性名</param>
  246. protected void CheckAndRemoveMemberDest(string properyName)
  247. {
  248. Predicate<MemberAssignment> exp = m => m.Member.Name == properyName;
  249. if (memberForNew.Exists(exp))
  250. {
  251. memberForNew.RemoveAll(exp);
  252. }
  253. }
  254. /// <summary>
  255. /// 获取成员初始化表达式。
  256. /// </summary>
  257. /// <returns></returns>
  258. protected MemberInitExpression GetMemberInitExpression()
  259. {
  260. return Expression.MemberInit(Expression.New(GetDestinationType()), MemberToMapForNew);
  261. }
  262. /// <summary>
  263. /// 创建成员绑定。
  264. /// </summary>
  265. /// <param name="propertyExpression">属性表达式</param>
  266. /// <param name="propertyTarget">目标属性</param>
  267. /// <param name="checkIfNull">是否检查null值</param>
  268. protected void CreateMemberBinding(Expression propertyExpression, MemberInfo propertyTarget, bool checkIfNull)
  269. {
  270. // 访问表达式进行转换
  271. memberForNew.Add(Expression.Bind(propertyTarget, visitorMapper.Visit(propertyExpression, checkIfNull)));
  272. }
  273. /// <summary>
  274. /// 将表达式源的映射分配给属性目标。
  275. /// </summary>
  276. /// <param name="getPropertySource">属性源类型</param>
  277. /// <param name="getPropertyDest">属性目标类型</param>
  278. /// <param name="checkIfNull">是否检查null值</param>
  279. /// <param name="name">要使用的映射器的别名</param>
  280. internal MapperConfigurationBase ForMemberBase(Expression getPropertySource, Expression getPropertyDest, bool checkIfNull, string name = null)
  281. {
  282. // 添加到映射列表并且可以继续操作
  283. PropertiesMapping.Add(Tuple.Create(getPropertySource, getPropertyDest, checkIfNull, name));
  284. return this;
  285. }
  286. /// <summary>
  287. /// 获取属性信息。
  288. /// </summary>
  289. /// <param name="propertyExpression">属性表达式树</param>
  290. /// <returns></returns>
  291. /// <exception cref="System.NotImplementedException">
  292. /// 这种表达方式不承担职责,或者这种类型的表达式是无效的
  293. /// </exception>
  294. protected static PropertyInfo GetPropertyInfo(Expression propertyExpression)
  295. {
  296. var expressionToAnalyse = propertyExpression.NodeType == ExpressionType.Lambda ? (propertyExpression as LambdaExpression).Body : propertyExpression;
  297. switch (expressionToAnalyse.NodeType)
  298. {
  299. case ExpressionType.Convert:
  300. Expression operand = (expressionToAnalyse as UnaryExpression).Operand;
  301. return operand.NodeType switch
  302. {
  303. ExpressionType.MemberAccess => ((operand as MemberExpression).Member as PropertyInfo),
  304. _ => throw new NotImplementedException("这种表达方式目前尚未支持")
  305. };
  306. case ExpressionType.MemberAccess:
  307. return (expressionToAnalyse as MemberExpression).Member as PropertyInfo;
  308. default:
  309. throw new NotImplementedException("这种表达方式目前尚未支持");
  310. }
  311. }
  312. internal void Initialize(Func<Type, object> constructor)
  313. {
  314. CreateMappingExpression(constructor);
  315. CreateMemberAssignementForExistingTarget();
  316. }
  317. /// <summary>
  318. /// 为现有目标对象创建成员
  319. /// </summary>
  320. public virtual void CreateMemberAssignementForExistingTarget()
  321. {
  322. if (PropertiesMapping.Count <= 0)
  323. {
  324. return;
  325. }
  326. // 用于更改原始表达式的参数。
  327. var paramTarget = Expression.Parameter(TargetType, paramClassSource.Name.Replace("s", "t"));
  328. var finalAssign = new List<Expression>();
  329. foreach (var item in PropertiesMapping)
  330. {
  331. var propToAssign = new ChangParameterExpressionVisitor(paramTarget).Visit(item.Item2);
  332. var assignExpression = new ChangParameterExpressionVisitor(paramClassSource).Visit(item.Item1);
  333. var sourceType = TypeSystem.GetElementType(item.Item2.Type);
  334. var targetType = TypeSystem.GetElementType(item.Item1.Type);
  335. if (string.IsNullOrEmpty(item.Item4))
  336. {
  337. object defaultValue = MapperHelper.GetDefaultValue(item.Item2.Type);
  338. Expression defaultExpression = Expression.Constant(defaultValue, item.Item2.Type);
  339. Expression checkIfNull = Expression.NotEqual(assignExpression, defaultExpression);
  340. if (item.Item3)
  341. {
  342. Expression setIf = Expression.IfThen(checkIfNull, Expression.Assign(propToAssign, assignExpression));
  343. finalAssign.Add(setIf);
  344. }
  345. else
  346. {
  347. if (!IsListOf(propToAssign.Type))
  348. {
  349. finalAssign.Add(Expression.Assign(propToAssign, assignExpression));
  350. }
  351. else
  352. {
  353. if (sourceType == targetType)
  354. {
  355. Expression toListExp = Expression.Call(_toListMethod.MakeGenericMethod(sourceType), assignExpression);
  356. Expression setIf = Expression.IfThen(checkIfNull, Expression.Assign(propToAssign, assignExpression));
  357. finalAssign.Add(setIf);
  358. finalAssign.Add(toListExp);
  359. }
  360. }
  361. }
  362. }
  363. else // 来自其他映射器。
  364. {
  365. var mapper = GetMapper(sourceType, targetType, false, item.Item4);
  366. if (mapper == null)
  367. {
  368. continue;
  369. }
  370. mapper.Initialize(_constructorFunc);
  371. Expression defaultExpression = Expression.Constant(MapperHelper.GetDefaultValue(item.Item2.Type), item.Item2.Type);
  372. if (!IsListOf(propToAssign.Type))
  373. {
  374. ChangParameterExpressionVisitor changeVisitor = new ChangParameterExpressionVisitor(propToAssign, assignExpression);
  375. Expression modifiedExpression = changeVisitor.Visit(mapper.expressionForExisting.Body);
  376. Expression checkIfNull = Expression.NotEqual(propToAssign, defaultExpression);
  377. Expression setIf = Expression.IfThen(checkIfNull, modifiedExpression);
  378. assignExpression = setIf;
  379. }
  380. else
  381. {
  382. Expression checkIfNull = Expression.NotEqual(propToAssign, defaultExpression);
  383. Expression setIf = Expression.IfThen(checkIfNull, Expression.Assign(propToAssign, assignExpression));
  384. assignExpression = setIf;
  385. }
  386. finalAssign.Add(assignExpression);
  387. }
  388. }
  389. if (finalAssign.Count > 0 && _delegateCallForExisting == null)
  390. {
  391. expressionForExisting = Expression.Lambda(Expression.Block(typeof(void), finalAssign), paramClassSource, paramTarget);
  392. // 编译
  393. _delegateCallForExisting = expressionForExisting.Compile();
  394. }
  395. }
  396. internal Expression GetLambdaDest(string propertyName)
  397. {
  398. var exp = PropertiesMapping.Find(x => GetPropertyInfo(x.Item1).Name == propertyName);
  399. if (exp != null)
  400. {
  401. var final = exp.Item2;
  402. if (final.NodeType == ExpressionType.Convert)
  403. {
  404. final = (final as UnaryExpression).Operand;
  405. }
  406. return final;
  407. }
  408. return null;
  409. }
  410. /// <summary>
  411. /// 创建映射表达式树
  412. /// </summary>
  413. /// <param name="constructor"></param>
  414. public virtual void CreateMappingExpression(Func<Type, object> constructor)
  415. {
  416. if (_isInitialized)
  417. {
  418. return;
  419. }
  420. // 它是在处理前放置以避免递归循环。
  421. _isInitialized = true;
  422. _constructorFunc = constructor;
  423. CreateCommonMember();
  424. var propsToAnalyse = PropertiesMapping.ToList(); // 克隆列表以便于更改。
  425. for (int i = 0; i < propsToAnalyse.Count; i++)
  426. {
  427. var propToAnalyse = propsToAnalyse[i];
  428. CheckAndConfigureMapping(ref propToAnalyse);
  429. propsToAnalyse[i] = propToAnalyse;
  430. }
  431. PropertiesMapping = propsToAnalyse;
  432. // 编译
  433. GetDelegate();
  434. }
  435. internal Type GetRealType(Type typeToFind)
  436. {
  437. return UseServiceLocator ? _constructorFunc(typeToFind).GetType() : typeToFind;
  438. }
  439. internal PropertiesNotMapped GetPropertiesNotMapped()
  440. {
  441. // 克隆属性信息
  442. var sourceProperties = SourceType.GetProperties().ToList();
  443. var targetProperties = TargetType.GetProperties().ToList();
  444. var visitor = new PropertiesVisitor(TargetType);
  445. foreach (var members in memberForNew)
  446. {
  447. var members1 = members;
  448. sourceProperties.RemoveAll((p) => members1.Member.Name == p.Name);
  449. targetProperties.RemoveAll((p) => visitor.GetProperties(members.Expression).Contains(p));
  450. }
  451. // 检查被忽略映射的成员
  452. sourceProperties.RemoveAll((p) => _propertiesToIgnore.Contains(p));
  453. return new PropertiesNotMapped
  454. {
  455. sourceProperties = sourceProperties,
  456. targetProperties = targetProperties
  457. };
  458. }
  459. /// <summary>
  460. /// 获取排序表达式树
  461. /// </summary>
  462. /// <param name="propertySource">属性名</param>
  463. /// <returns></returns>
  464. public LambdaExpression GetSortedExpression(string propertySource)
  465. {
  466. var exp = PropertiesMapping.Find(x => GetPropertyInfo(x.Item2).Name == propertySource);
  467. if (exp == null)
  468. {
  469. throw new PropertyNoExistException(propertySource, TargetType);
  470. }
  471. // 更改参数
  472. var visitor = new MapperExpressionVisitor(paramClassSource);
  473. var result = visitor.Visit(exp.Item1);
  474. return Expression.Lambda(result, paramClassSource);
  475. }
  476. private static bool IsListOf(Type typeTarget)
  477. {
  478. // 特殊情况字符串是char数组。
  479. if (typeTarget == typeof(string))
  480. {
  481. return false;
  482. }
  483. Func<Type, bool> test = t => t.IsAssignableFrom(typeof(IEnumerable));
  484. return test(typeTarget) || typeTarget.GetInterfaces().Any(test);
  485. }
  486. private MapperConfigurationBase GetAndCheckMapper(Type typeOfSource, Type typeOfTarget, string name)
  487. {
  488. var externalMapper = GetMapper(typeOfSource, typeOfTarget, false, name);
  489. if (externalMapper != null)
  490. {
  491. return externalMapper;
  492. }
  493. //如果找不到具有别名的映射器
  494. if (!string.IsNullOrEmpty(name))
  495. {
  496. throw new NoFoundMapperException(name);
  497. }
  498. throw new NotSameTypePropertyException(typeOfSource, typeOfTarget);
  499. }
  500. private void CreatBindingFromSimple(ref Tuple<Expression, Expression, bool, string> configExpression, Type typeSource, Type typeTarget, PropertyInfo propTarget)
  501. {
  502. // 没有特殊的操作
  503. if (typeSource == typeTarget)
  504. {
  505. // 创建成员绑定
  506. CreateMemberBinding(configExpression.Item1, propTarget, configExpression.Item3);
  507. }
  508. else
  509. {
  510. // 尝试查找mapper
  511. var externalMapper = GetAndCheckMapper(typeSource, typeTarget, configExpression.Item4);
  512. // 如果此时未初始化映射器
  513. externalMapper.CreateMappingExpression(_constructorFunc);
  514. // 默认情况下,检查对象的null
  515. Expression mapExpression = externalMapper.GetMemberInitExpression();
  516. Expression defaultExpression = Expression.Constant(MapperHelper.GetDefaultValue(configExpression.Item1.Type), configExpression.Item1.Type);
  517. // 修改成员
  518. var expSource = visitorMapper.Visit(configExpression.Item1);
  519. var changeParamaterVisitor = new ChangParameterExpressionVisitor(expSource);
  520. mapExpression = changeParamaterVisitor.Visit(mapExpression);
  521. // 现在可以创建正确的参数。
  522. Expression checkIfNull = Expression.NotEqual(expSource, defaultExpression);
  523. // 创建条件
  524. var checkExpression = Expression.Condition(checkIfNull, mapExpression, Expression.Constant(MapperHelper.GetDefaultValue(mapExpression.Type), mapExpression.Type), mapExpression.Type);
  525. var bindExpression = Expression.Bind(propTarget, checkExpression);
  526. // 找到了映射器但没有配置
  527. if (string.IsNullOrEmpty(configExpression.Item4))
  528. {
  529. configExpression = Tuple.Create(configExpression.Item1, configExpression.Item2, configExpression.Item3, externalMapper.Name);
  530. }
  531. memberForNew.Add(bindExpression);
  532. }
  533. }
  534. private void CreateBindingFromList(ref Tuple<Expression, Expression, bool, string> configExpression, Type typeSource, Type typeTarget, PropertyInfo propTarget)
  535. {
  536. var sourceTypeList = TypeSystem.GetElementType(typeSource);
  537. var destTypeList = TypeSystem.GetElementType(typeTarget);
  538. if (sourceTypeList == destTypeList)
  539. {
  540. if (configExpression.Item2.NodeType == ExpressionType.MemberAccess)
  541. {
  542. CreateMemberBinding(configExpression.Item1, propTarget, configExpression.Item3);
  543. }
  544. }
  545. // 使用Enumerable类的select方法来更改类型
  546. else
  547. {
  548. var externalMapper = GetAndCheckMapper(sourceTypeList, destTypeList, configExpression.Item4);
  549. externalMapper.CreateMappingExpression(_constructorFunc);
  550. MemberAssignment expBind;
  551. var expSource = configExpression.Item1;
  552. var visitor = new ChangParameterExpressionVisitor(paramClassSource);
  553. expSource = visitor.Visit(expSource);
  554. // 为了与EF / LINQ2SQL兼容。
  555. var expMappeur = externalMapper.GetGenericLambdaExpression();
  556. // 创建对Select方法的调用,在Enumerable的Select中插入一个lambda表达式(参数是一个委托),通常情况下,这是不可能的,但(个人认为)编译器就像这样创建并且LINQ2SQL / EF是可以进行sql查询的
  557. Expression select = Expression.Call(_selectMethod.MakeGenericMethod(sourceTypeList, destTypeList), new[]
  558. {
  559. expSource,
  560. expMappeur
  561. });
  562. // 创建对ToList方法的调用
  563. Expression toList = Expression.Call(_toListMethod.MakeGenericMethod(destTypeList), select);
  564. if (configExpression.Item3) // 如果要检查无效(使用EF / LinqTosql,则不需要)。
  565. {
  566. // 测试source的属性是否为null。
  567. Expression checkIfNull = Expression.NotEqual(expSource, Expression.Constant(MapperHelper.GetDefaultValue(expSource.Type), expSource.Type));
  568. // 有时候ToList方法不起作用,则使用实现ToList不起作用的类
  569. Expression asExp = Expression.TypeAs(toList, propTarget.PropertyType);
  570. // 创建条件表达式
  571. Expression expCondition = Expression.Condition(checkIfNull, asExp, Expression.Constant(MapperHelper.GetDefaultValue(typeTarget), typeTarget));
  572. // 分配给目标属性。
  573. expBind = Expression.Bind(propTarget, expCondition);
  574. }
  575. else
  576. {
  577. // 分配给目标属性。
  578. expBind = Expression.Bind(propTarget, toList);
  579. }
  580. // 查找mapper
  581. if (string.IsNullOrEmpty(configExpression.Item4))
  582. {
  583. configExpression = Tuple.Create(configExpression.Item1, configExpression.Item2, configExpression.Item3, externalMapper.Name);
  584. }
  585. memberForNew.Add(expBind);
  586. }
  587. }
  588. }
  589. }