diff --git a/AgileMapper.Buildable.UnitTests.NetCore3/AgileMapper.Buildable.UnitTests.NetCore3.csproj b/AgileMapper.Buildable.UnitTests.NetCore3/AgileMapper.Buildable.UnitTests.NetCore3.csproj new file mode 100644 index 000000000..2a205221e --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetCore3/AgileMapper.Buildable.UnitTests.NetCore3.csproj @@ -0,0 +1,41 @@ + + + + netcoreapp3.1 + AgileObjects.AgileMapper.Buildable.UnitTests.NetCore3 + AgileObjects.AgileMapper.Buildable.UnitTests + true + + 0649;1701;1702 + false + + + + true + ..\AgileMapper.Buildable.UnitTests.NetStandard2.Mappers\AgileMapper.Buildable.UnitTests.NetStandard2.Mappers.csproj + + + + + %(RecursiveDir)%(Filename)%(Extension) + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Generator/AgileMapper.Buildable.UnitTests.NetStandard2.Generator.csproj b/AgileMapper.Buildable.UnitTests.NetStandard2.Generator/AgileMapper.Buildable.UnitTests.NetStandard2.Generator.csproj new file mode 100644 index 000000000..4309960f6 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Generator/AgileMapper.Buildable.UnitTests.NetStandard2.Generator.csproj @@ -0,0 +1,31 @@ + + + + netstandard2.0 + AgileObjects.AgileMapper.Buildable.UnitTests.NetStandard2.Generator + AgileObjects.AgileMapper.Buildable.UnitTests.Generator + + + + false + ..\AgileMapper.Buildable.UnitTests.NetStandard2.Mappers\AgileMapper.Buildable.UnitTests.NetStandard2.Mappers.csproj + + + + + MapperConfiguration\%(RecursiveDir)%(Filename)%(Extension) + + + MapperConfiguration\%(RecursiveDir)%(Filename)%(Extension) + + + + + + + + + + + + diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers.csproj b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers.csproj new file mode 100644 index 000000000..2864f9f03 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers.csproj @@ -0,0 +1,13 @@ + + + + netstandard2.0 + AgileObjects.AgileMapper.Buildable.UnitTests.NetStandard2.Mappers + AgileObjects.AgileMapper.Buildable.UnitTests + + + + + + + diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/AddressAddressPublicTwoFieldsMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/AddressAddressPublicTwoFieldsMapper.cs new file mode 100644 index 000000000..a980cbae6 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/AddressAddressPublicTwoFieldsMapper.cs @@ -0,0 +1,118 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class AddressAddressPublicTwoFieldsMapper : MappingExecutionContextBase> + { + public AddressAddressPublicTwoFieldsMapper + ( + PublicTwoFields source + ) + : base(source) + { + } + + public PublicTwoFields ToANew() + where TTarget : PublicTwoFields + { + return AddressAddressPublicTwoFieldsMapper.CreateNew(this.CreateRootMappingData(default(PublicTwoFields))); + } + + private static PublicTwoFields CreateNew + ( + IObjectMappingData, PublicTwoFields> aaptfToAaptfData + ) + { + PublicTwoFields sourceAddressAddressPublicTwoFields; + try + { + sourceAddressAddressPublicTwoFields = aaptfToAaptfData.Source; + + var addressAddressPublicTwoFields = new PublicTwoFields(); + + if (sourceAddressAddressPublicTwoFields.Value1 != null) + { + addressAddressPublicTwoFields.Value1 = AddressAddressPublicTwoFieldsMapper.GetAddress1(addressAddressPublicTwoFields, sourceAddressAddressPublicTwoFields); + } + + if (sourceAddressAddressPublicTwoFields.Value2 != null) + { + addressAddressPublicTwoFields.Value2 = AddressAddressPublicTwoFieldsMapper.GetAddress2(addressAddressPublicTwoFields, sourceAddressAddressPublicTwoFields); + } + + return addressAddressPublicTwoFields; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicTwoFields", + "PublicTwoFields", + ex); + } + } + + private static Address GetAddress1 + ( + PublicTwoFields addressAddressPublicTwoFields, + PublicTwoFields sourceAddressAddressPublicTwoFields + ) + { + try + { + var address = addressAddressPublicTwoFields.Value1 ?? new Address(); + address.Line1 = sourceAddressAddressPublicTwoFields.Value1.Line1; + address.Line2 = sourceAddressAddressPublicTwoFields.Value1.Line2; + + return address; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicTwoFields.Value1", + "PublicTwoFields.Value1", + ex); + } + } + + private static Address GetAddress2 + ( + PublicTwoFields addressAddressPublicTwoFields, + PublicTwoFields sourceAddressAddressPublicTwoFields + ) + { + try + { + var address = addressAddressPublicTwoFields.Value2 ?? new Address(); + address.Line1 = sourceAddressAddressPublicTwoFields.Value2.Line1; + address.Line2 = sourceAddressAddressPublicTwoFields.Value2.Line2; + + return address; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicTwoFields.Value2", + "PublicTwoFields.Value2", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/AddressMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/AddressMapper.cs new file mode 100644 index 000000000..e25279b40 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/AddressMapper.cs @@ -0,0 +1,97 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class AddressMapper : MappingExecutionContextBase
+ { + public AddressMapper + ( + Address source + ) + : base(source) + { + } + + public Address OnTo + ( + Address target + ) + { + return AddressMapper.Merge(this.CreateRootMappingData(target)); + } + + public Address Over + ( + Address target + ) + { + return AddressMapper.Overwrite(this.CreateRootMappingData(target)); + } + + private static Address Merge + ( + IObjectMappingData aToAData + ) + { + try + { + if (aToAData.Target.Line1 == null) + { + aToAData.Target.Line1 = aToAData.Source.Line1; + } + + if (aToAData.Target.Line2 == null) + { + aToAData.Target.Line2 = aToAData.Source.Line2; + } + + return aToAData.Target; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Address", + "Address", + ex); + } + } + + private static Address Overwrite + ( + IObjectMappingData aToAData + ) + { + try + { + aToAData.Target.Line1 = aToAData.Source.Line1; + aToAData.Target.Line2 = aToAData.Source.Line2; + + return aToAData.Target; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "Address", + "Address", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/CharArrayMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/CharArrayMapper.cs new file mode 100644 index 000000000..f7d8cd8e4 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/CharArrayMapper.cs @@ -0,0 +1,67 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Linq; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.ObjectPopulation; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class CharArrayMapper : MappingExecutionContextBase + { + public CharArrayMapper + ( + char[] source + ) + : base(source) + { + } + + public int[] Over + ( + int[] target + ) + { + return CharArrayMapper.Overwrite(this.CreateRootMappingData(target)); + } + + private static int[] Overwrite + ( + IObjectMappingData caToIaData + ) + { + try + { + return caToIaData.Source.Project(c => CharArrayMapper.GetInt(c)).ToArray(); + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "char[]", + "int[]", + ex); + } + } + + private static int GetInt + ( + char c + ) + { + int intValue; + return int.TryParse(c.ToString(), out intValue) ? intValue : default(int); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ChildMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ChildMapper.cs new file mode 100644 index 000000000..a004986c5 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ChildMapper.cs @@ -0,0 +1,170 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class ChildMapper : MappingExecutionContextBase + { + public ChildMapper + ( + Child source + ) + : base(source) + { + } + + public Child ToANew() + where TTarget : Child + { + return ChildMapper.CreateNew(this.CreateRootMappingData(default(Child))); + } + + private static Child MapRepeated + ( + IObjectMappingData cToCData2 + ) + { + try + { + Child child; + + if (cToCData2.TryGet(cToCData2.Source, out child)) + { + return child; + } + + child = cToCData2.Target ?? new Child(); + cToCData2.Register(cToCData2.Source, child); + child.Name = cToCData2.Source.Name; + + if (cToCData2.Source.EldestParent != null) + { + child.EldestParent = ChildMapper.MapRepeated( + MappingExecutionContextBase.CreateChildMappingData(cToCData2.Source.EldestParent, child.EldestParent, cToCData2)); + } + + return child; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Child.EldestParent.EldestChild", + "Child.EldestParent.EldestChild", + ex); + } + } + + private static Parent MapRepeated + ( + IObjectMappingData pToPData2 + ) + { + try + { + Parent parent; + + if (pToPData2.TryGet(pToPData2.Source, out parent)) + { + return parent; + } + + parent = pToPData2.Target ?? new Parent(); + pToPData2.Register(pToPData2.Source, parent); + parent.Name = pToPData2.Source.Name; + + if (pToPData2.Source.EldestChild != null) + { + parent.EldestChild = ChildMapper.MapRepeated( + MappingExecutionContextBase.CreateChildMappingData(pToPData2.Source.EldestChild, parent.EldestChild, pToPData2)); + } + + return parent; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Child.EldestChild.EldestParent", + "Child.EldestParent.EldestChild.EldestParent", + ex); + } + } + + private static Child CreateNew + ( + IObjectMappingData cToCData + ) + { + Child sourceChild; + try + { + sourceChild = cToCData.Source; + + var child = new Child(); + cToCData.Register(sourceChild, child); + child.Name = sourceChild.Name; + + if (sourceChild.EldestParent != null) + { + child.EldestParent = ChildMapper.GetParent(child, cToCData, sourceChild); + } + + return child; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Child", + "Child", + ex); + } + } + + private static Parent GetParent + ( + Child child, + IObjectMappingData cToCData, + Child sourceChild + ) + { + try + { + var parent = child.EldestParent ?? new Parent(); + cToCData.Register(sourceChild.EldestParent, parent); + parent.Name = sourceChild.EldestParent.Name; + + if (sourceChild.EldestParent.EldestChild != null) + { + parent.EldestChild = ChildMapper.MapRepeated( + MappingExecutionContextBase.CreateChildMappingData(sourceChild.EldestParent.EldestChild, parent.EldestChild, cToCData)); + } + + return parent; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Child.EldestParent", + "Child.EldestParent", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/DateTimeHashSetMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/DateTimeHashSetMapper.cs new file mode 100644 index 000000000..a01419066 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/DateTimeHashSetMapper.cs @@ -0,0 +1,85 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.ReadableExpressions; +using AgileObjects.ReadableExpressions.Extensions; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class DateTimeHashSetMapper : MappingExecutionContextBase> + { + public DateTimeHashSetMapper + ( + HashSet source + ) + : base(source) + { + } + + public TTarget ToANew() + { + if (typeof(TTarget) == typeof(DateTime[])) + { + return (TTarget)((object)DateTimeHashSetMapper.CreateNew(this.CreateRootMappingData(default(DateTime[])))); + } + + throw new NotSupportedException( + "Unable to perform a 'CreateNew' mapping from source type 'HashSet' to target type '" + typeof(TTarget).GetFriendlyName(null) + "'"); + } + + private static DateTime[] CreateNew + ( + IObjectMappingData, DateTime[]> dthsToDtaData + ) + { + try + { + var sourceDateTimeHashSet = dthsToDtaData.Source; + var targetDateTimeList = new List(sourceDateTimeHashSet.Count); + var i = 0; + var enumerator = sourceDateTimeHashSet.GetEnumerator(); + try + { + while (true) + { + if (!enumerator.MoveNext()) + { + break; + } + + targetDateTimeList.Add(enumerator.Current); + ++i; + } + } + finally + { + enumerator.Dispose(); + } + + return targetDateTimeList.ToArray(); + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "HashSet", + "DateTime[]", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/DecimalArrayMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/DecimalArrayMapper.cs new file mode 100644 index 000000000..b5576c953 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/DecimalArrayMapper.cs @@ -0,0 +1,80 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.ObjectPopulation; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class DecimalArrayMapper : MappingExecutionContextBase + { + public DecimalArrayMapper + ( + decimal[] source + ) + : base(source) + { + } + + public HashSet OnTo + ( + HashSet target + ) + { + return DecimalArrayMapper.Merge(this.CreateRootMappingData(target)); + } + + private static HashSet Merge + ( + IObjectMappingData> daToDhsData + ) + { + try + { + var sourceDoubleIEnumerable = daToDhsData.Source.Project(d => (double)d).Exclude(daToDhsData.Target); + var targetDoubleHashSet = daToDhsData.Target; + var i = 0; + var enumerator = sourceDoubleIEnumerable.GetEnumerator(); + try + { + while (true) + { + if (!enumerator.MoveNext()) + { + break; + } + + targetDoubleHashSet.Add(enumerator.Current); + ++i; + } + } + finally + { + enumerator.Dispose(); + } + + return targetDoubleHashSet; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "decimal[]", + "HashSet", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/Extensions/MappingExtensions.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/Extensions/MappingExtensions.cs new file mode 100644 index 000000000..987d137ce --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/Extensions/MappingExtensions.cs @@ -0,0 +1,199 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using AgileObjects.AgileMapper.Buildable.UnitTests.Mappers; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers.Extensions +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public static class MappingExtensions + { + public static AddressAddressPublicTwoFieldsMapper Map + ( + this PublicTwoFields source + ) + { + return new AddressAddressPublicTwoFieldsMapper(source); + } + + public static PublicTwoFields DeepClone + ( + this PublicTwoFields source + ) + { + return new AddressAddressPublicTwoFieldsMapper(source).ToANew>(); + } + + public static AddressMapper Map + ( + this Address source + ) + { + return new AddressMapper(source); + } + + public static CharArrayMapper Map + ( + this char[] source + ) + { + return new CharArrayMapper(source); + } + + public static ChildMapper Map + ( + this Child source + ) + { + return new ChildMapper(source); + } + + public static Child DeepClone + ( + this Child source + ) + { + return new ChildMapper(source).ToANew(); + } + + public static DateTimeHashSetMapper Map + ( + this HashSet source + ) + { + return new DateTimeHashSetMapper(source); + } + + public static DecimalArrayMapper Map + ( + this decimal[] source + ) + { + return new DecimalArrayMapper(source); + } + + public static IntAddressPublicTwoFieldsMapper Map + ( + this PublicTwoFields source + ) + { + return new IntAddressPublicTwoFieldsMapper(source); + } + + public static IntArrayMapper Map + ( + this int[] source + ) + { + return new IntArrayMapper(source); + } + + public static IntIEnumerableMapper Map + ( + this IEnumerable source + ) + { + return new IntIEnumerableMapper(source); + } + + public static IntStringIntToTargetValueSourceMapper Map + ( + this ToTargetValueSource source + ) + { + return new IntStringIntToTargetValueSourceMapper(source); + } + + public static ProductArrayMapper Map + ( + this Product[] source + ) + { + return new ProductArrayMapper(source); + } + + public static ProductDtoArrayMapper Map + ( + this ProductDto[] source + ) + { + return new ProductDtoArrayMapper(source); + } + + public static ProductDtoListMapper Map + ( + this List source + ) + { + return new ProductDtoListMapper(source); + } + + public static ProductMapper Map + ( + this Product source + ) + { + return new ProductMapper(source); + } + + public static StringCollectionMapper Map + ( + this Collection source + ) + { + return new StringCollectionMapper(source); + } + + public static StringListMapper Map + ( + this List source + ) + { + return new StringListMapper(source); + } + + public static StringMapper Map + ( + this string source + ) + { + return new StringMapper(source); + } + + public static StringPublicFieldMapper Map + ( + this PublicField source + ) + { + return new StringPublicFieldMapper(source); + } + + public static StringPublicPropertyMapper Map + ( + this PublicProperty source + ) + { + return new StringPublicPropertyMapper(source); + } + + public static StringStringDictionaryMapper Map + ( + this Dictionary source + ) + { + return new StringStringDictionaryMapper(source); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/IntAddressPublicTwoFieldsMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/IntAddressPublicTwoFieldsMapper.cs new file mode 100644 index 000000000..e028d9ace --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/IntAddressPublicTwoFieldsMapper.cs @@ -0,0 +1,65 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class IntAddressPublicTwoFieldsMapper : MappingExecutionContextBase> + { + public IntAddressPublicTwoFieldsMapper + ( + PublicTwoFields source + ) + : base(source) + { + } + + public Dictionary ToANew() + where TTarget : Dictionary + { + return IntAddressPublicTwoFieldsMapper.CreateNew(this.CreateRootMappingData(default(Dictionary))); + } + + private static Dictionary CreateNew + ( + IObjectMappingData, Dictionary> iaptfToSsdData + ) + { + try + { + var stringStringDictionary = new Dictionary(); + stringStringDictionary["Value1"] = iaptfToSsdData.Source.Value1.ToString(); + + if (iaptfToSsdData.Source.Value2 != null) + { + stringStringDictionary["Value2.Line1"] = iaptfToSsdData.Source.Value2.Line1; + stringStringDictionary["Value2.Line2"] = iaptfToSsdData.Source.Value2.Line2; + } + + return stringStringDictionary; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicTwoFields", + "Dictionary", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/IntArrayMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/IntArrayMapper.cs new file mode 100644 index 000000000..496a2e484 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/IntArrayMapper.cs @@ -0,0 +1,70 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class IntArrayMapper : MappingExecutionContextBase + { + public IntArrayMapper + ( + int[] source + ) + : base(source) + { + } + + public ReadOnlyCollection ToANew() + where TTarget : ReadOnlyCollection + { + return IntArrayMapper.CreateNew(this.CreateRootMappingData(default(ReadOnlyCollection))); + } + + private static ReadOnlyCollection CreateNew + ( + IObjectMappingData> iaToIrocData + ) + { + try + { + var sourceIntArray = iaToIrocData.Source; + var targetIntList = new List(sourceIntArray.Length); + var i = 0; + while (true) + { + if (i == sourceIntArray.Length) + { + break; + } + + targetIntList.Add(sourceIntArray[i]); + ++i; + } + + return targetIntList.AsReadOnly(); + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "int[]", + "ReadOnlyCollection", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/IntIEnumerableMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/IntIEnumerableMapper.cs new file mode 100644 index 000000000..f9fe81aa9 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/IntIEnumerableMapper.cs @@ -0,0 +1,80 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.ObjectPopulation; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class IntIEnumerableMapper : MappingExecutionContextBase> + { + public IntIEnumerableMapper + ( + IEnumerable source + ) + : base(source) + { + } + + public ICollection OnTo + ( + ICollection target + ) + { + return IntIEnumerableMapper.Merge(this.CreateRootMappingData(target)); + } + + private static ICollection Merge + ( + IObjectMappingData, ICollection> iieToIicData + ) + { + try + { + var sourceIntIEnumerable = iieToIicData.Source.Exclude(iieToIicData.Target); + ICollection targetIntICollection = iieToIicData.Target.IsReadOnly ? new List(iieToIicData.Target) : iieToIicData.Target; + var i = 0; + var enumerator = sourceIntIEnumerable.GetEnumerator(); + try + { + while (true) + { + if (!enumerator.MoveNext()) + { + break; + } + + targetIntICollection.Add(enumerator.Current); + ++i; + } + } + finally + { + enumerator.Dispose(); + } + + return targetIntICollection; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "IEnumerable", + "ICollection", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/IntStringIntToTargetValueSourceMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/IntStringIntToTargetValueSourceMapper.cs new file mode 100644 index 000000000..ab63e2a18 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/IntStringIntToTargetValueSourceMapper.cs @@ -0,0 +1,218 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class IntStringIntToTargetValueSourceMapper : MappingExecutionContextBase> + { + public IntStringIntToTargetValueSourceMapper + ( + ToTargetValueSource source + ) + : base(source) + { + } + + public PublicTwoFields ToANew() + where TTarget : PublicTwoFields + { + return IntStringIntToTargetValueSourceMapper.CreateNew(this.CreateRootMappingData(default(PublicTwoFields))); + } + + public PublicTwoFields Over + ( + PublicTwoFields target + ) + { + return IntStringIntToTargetValueSourceMapper.Overwrite(this.CreateRootMappingData(target)); + } + + public PublicTwoFields OnTo + ( + PublicTwoFields target + ) + { + return IntStringIntToTargetValueSourceMapper.Merge(this.CreateRootMappingData(target)); + } + + private static PublicTwoFields CreateNew + ( + IObjectMappingData, PublicTwoFields> isittvsToIiptfData + ) + { + ToTargetValueSource sourceIntStringIntToTargetValueSource; + try + { + sourceIntStringIntToTargetValueSource = isittvsToIiptfData.Source; + + var intIntPublicTwoFields = new PublicTwoFields(); + intIntPublicTwoFields.Value1 = sourceIntStringIntToTargetValueSource.Value1; + // No data sources for Value2 + + if (sourceIntStringIntToTargetValueSource.Value != null) + { + if (sourceIntStringIntToTargetValueSource.Value != null) + { + intIntPublicTwoFields.Value1 = IntStringIntToTargetValueSourceMapper.GetInt1(sourceIntStringIntToTargetValueSource); + } + + if (sourceIntStringIntToTargetValueSource.Value != null) + { + intIntPublicTwoFields.Value2 = sourceIntStringIntToTargetValueSource.Value.Value2; + } + } + + return intIntPublicTwoFields; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "ToTargetValueSource", + "PublicTwoFields", + ex); + } + } + + private static PublicTwoFields Overwrite + ( + IObjectMappingData, PublicTwoFields> isittvsToIiptfData + ) + { + ToTargetValueSource sourceIntStringIntToTargetValueSource; + try + { + sourceIntStringIntToTargetValueSource = isittvsToIiptfData.Source; + + isittvsToIiptfData.Target.Value1 = sourceIntStringIntToTargetValueSource.Value1; + // No data sources for Value2 + + if (sourceIntStringIntToTargetValueSource.Value != null) + { + if (sourceIntStringIntToTargetValueSource.Value != null) + { + isittvsToIiptfData.Target.Value1 = IntStringIntToTargetValueSourceMapper.GetInt2(sourceIntStringIntToTargetValueSource); + } + else + { + isittvsToIiptfData.Target.Value1 = default(int); + } + + if (sourceIntStringIntToTargetValueSource.Value != null) + { + isittvsToIiptfData.Target.Value2 = sourceIntStringIntToTargetValueSource.Value.Value2; + } + else + { + isittvsToIiptfData.Target.Value2 = default(int); + } + } + + return isittvsToIiptfData.Target; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ToTargetValueSource", + "PublicTwoFields", + ex); + } + } + + private static PublicTwoFields Merge + ( + IObjectMappingData, PublicTwoFields> isittvsToIiptfData + ) + { + ToTargetValueSource sourceIntStringIntToTargetValueSource; + try + { + sourceIntStringIntToTargetValueSource = isittvsToIiptfData.Source; + + if (isittvsToIiptfData.Target.Value1 == default(int)) + { + isittvsToIiptfData.Target.Value1 = sourceIntStringIntToTargetValueSource.Value1; + } + + // No data sources for Value2 + + if (sourceIntStringIntToTargetValueSource.Value != null) + { + if (isittvsToIiptfData.Target.Value1 == default(int)) + { + if (sourceIntStringIntToTargetValueSource.Value != null) + { + isittvsToIiptfData.Target.Value1 = IntStringIntToTargetValueSourceMapper.GetInt3(sourceIntStringIntToTargetValueSource); + } + } + + if (isittvsToIiptfData.Target.Value2 == default(int)) + { + if (sourceIntStringIntToTargetValueSource.Value != null) + { + isittvsToIiptfData.Target.Value2 = sourceIntStringIntToTargetValueSource.Value.Value2; + } + } + } + + return isittvsToIiptfData.Target; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "ToTargetValueSource", + "PublicTwoFields", + ex); + } + } + + private static int GetInt1 + ( + ToTargetValueSource sourceIntStringIntToTargetValueSource + ) + { + int intValue; + return int.TryParse(sourceIntStringIntToTargetValueSource.Value.Value1, out intValue) + ? intValue + : default(int); + } + + private static int GetInt2 + ( + ToTargetValueSource sourceIntStringIntToTargetValueSource + ) + { + int intValue; + return int.TryParse(sourceIntStringIntToTargetValueSource.Value.Value1, out intValue) + ? intValue + : default(int); + } + + private static int GetInt3 + ( + ToTargetValueSource sourceIntStringIntToTargetValueSource + ) + { + int intValue; + return int.TryParse(sourceIntStringIntToTargetValueSource.Value.Value1, out intValue) + ? intValue + : default(int); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/Mapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/Mapper.cs new file mode 100644 index 000000000..b029798ae --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/Mapper.cs @@ -0,0 +1,198 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public static class Mapper + { + public static AddressAddressPublicTwoFieldsMapper Map + ( + PublicTwoFields source + ) + { + return new AddressAddressPublicTwoFieldsMapper(source); + } + + public static PublicTwoFields DeepClone + ( + PublicTwoFields source + ) + { + return new AddressAddressPublicTwoFieldsMapper(source).ToANew>(); + } + + public static AddressMapper Map + ( + Address source + ) + { + return new AddressMapper(source); + } + + public static CharArrayMapper Map + ( + char[] source + ) + { + return new CharArrayMapper(source); + } + + public static ChildMapper Map + ( + Child source + ) + { + return new ChildMapper(source); + } + + public static Child DeepClone + ( + Child source + ) + { + return new ChildMapper(source).ToANew(); + } + + public static DateTimeHashSetMapper Map + ( + HashSet source + ) + { + return new DateTimeHashSetMapper(source); + } + + public static DecimalArrayMapper Map + ( + decimal[] source + ) + { + return new DecimalArrayMapper(source); + } + + public static IntAddressPublicTwoFieldsMapper Map + ( + PublicTwoFields source + ) + { + return new IntAddressPublicTwoFieldsMapper(source); + } + + public static IntArrayMapper Map + ( + int[] source + ) + { + return new IntArrayMapper(source); + } + + public static IntIEnumerableMapper Map + ( + IEnumerable source + ) + { + return new IntIEnumerableMapper(source); + } + + public static IntStringIntToTargetValueSourceMapper Map + ( + ToTargetValueSource source + ) + { + return new IntStringIntToTargetValueSourceMapper(source); + } + + public static ProductArrayMapper Map + ( + Product[] source + ) + { + return new ProductArrayMapper(source); + } + + public static ProductDtoArrayMapper Map + ( + ProductDto[] source + ) + { + return new ProductDtoArrayMapper(source); + } + + public static ProductDtoListMapper Map + ( + List source + ) + { + return new ProductDtoListMapper(source); + } + + public static ProductMapper Map + ( + Product source + ) + { + return new ProductMapper(source); + } + + public static StringCollectionMapper Map + ( + Collection source + ) + { + return new StringCollectionMapper(source); + } + + public static StringListMapper Map + ( + List source + ) + { + return new StringListMapper(source); + } + + public static StringMapper Map + ( + string source + ) + { + return new StringMapper(source); + } + + public static StringPublicFieldMapper Map + ( + PublicField source + ) + { + return new StringPublicFieldMapper(source); + } + + public static StringPublicPropertyMapper Map + ( + PublicProperty source + ) + { + return new StringPublicPropertyMapper(source); + } + + public static StringStringDictionaryMapper Map + ( + Dictionary source + ) + { + return new StringStringDictionaryMapper(source); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ProductArrayMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ProductArrayMapper.cs new file mode 100644 index 000000000..faba24256 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ProductArrayMapper.cs @@ -0,0 +1,291 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class ProductArrayMapper : MappingExecutionContextBase + { + public ProductArrayMapper + ( + Product[] source + ) + : base(source) + { + } + + public IEnumerable OnTo + ( + IEnumerable target + ) + { + return ProductArrayMapper.Merge(this.CreateRootMappingData(target)); + } + + private static IEnumerable Merge + ( + IObjectMappingData> paToPieData + ) + { + try + { + var collectionData = CollectionData.Create(paToPieData.Source, paToPieData.Target, p => p.ProductId); + collectionData.Intersection.ForEach( + (existingSourceProduct, existingTargetProduct, idx) => ProductArrayMapper.GetProduct1(existingSourceProduct, existingTargetProduct)); + var sourceProductIEnumerable = collectionData.NewSourceItems; + var targetProductICollection = ProductArrayMapper.GetProductICollection(paToPieData); + var i = 0; + var enumerator = sourceProductIEnumerable.GetEnumerator(); + try + { + while (true) + { + if (!enumerator.MoveNext()) + { + break; + } + + targetProductICollection.Add(ProductArrayMapper.GetProduct2(enumerator)); + ++i; + } + } + finally + { + enumerator.Dispose(); + } + + return targetProductICollection; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Product[]", + "IEnumerable", + ex); + } + } + + private static Product GetProduct1 + ( + Product existingSourceProduct, + Product existingTargetProduct + ) + { + try + { + if (existingSourceProduct == null) + { + return null; + } + + var sourceMegaProduct = existingSourceProduct as MegaProduct; + + if ((sourceMegaProduct != null) && ((existingTargetProduct == null) || (existingTargetProduct is MegaProduct))) + { + return ProductArrayMapper.GetMegaProduct1(existingTargetProduct, sourceMegaProduct); + } + + if (existingTargetProduct is MegaProduct) + { + return ProductArrayMapper.GetMegaProduct2(existingTargetProduct, existingSourceProduct); + } + var product = existingTargetProduct ?? new Product(); + + if (product.ProductId == null) + { + product.ProductId = existingSourceProduct.ProductId; + } + + if (product.Price == default(double)) + { + product.Price = existingSourceProduct.Price; + } + + return product; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Product[][i]", + "IEnumerable[i]", + ex); + } + } + + private static MegaProduct GetMegaProduct1 + ( + Product existingTargetProduct, + MegaProduct sourceMegaProduct + ) + { + try + { + var megaProduct = ((MegaProduct)existingTargetProduct) ?? new MegaProduct(); + + if (megaProduct.HowMega == default(decimal)) + { + megaProduct.HowMega = sourceMegaProduct.HowMega; + } + + if (megaProduct.ProductId == null) + { + megaProduct.ProductId = sourceMegaProduct.ProductId; + } + + if (megaProduct.Price == default(double)) + { + megaProduct.Price = sourceMegaProduct.Price; + } + + return megaProduct; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Product[][i]", + "IEnumerable[i]", + ex); + } + } + + private static MegaProduct GetMegaProduct2 + ( + Product existingTargetProduct, + Product existingSourceProduct + ) + { + try + { + var megaProduct = ((MegaProduct)existingTargetProduct) ?? new MegaProduct(); + // No data sources for HowMega + + if (megaProduct.ProductId == null) + { + megaProduct.ProductId = existingSourceProduct.ProductId; + } + + if (megaProduct.Price == default(double)) + { + megaProduct.Price = existingSourceProduct.Price; + } + + return megaProduct; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Product[][i]", + "IEnumerable[i]", + ex); + } + } + + private static ICollection GetProductICollection + ( + IObjectMappingData> paToPieData + ) + { + ICollection collection; + return ((collection = paToPieData.Target as ICollection) != null) + ? collection.IsReadOnly ? new List(paToPieData.Target) : collection + : new List(paToPieData.Target); + } + + private static Product GetProduct2 + ( + IEnumerator enumerator + ) + { + try + { + if (enumerator.Current == null) + { + return null; + } + + var sourceMegaProduct = enumerator.Current as MegaProduct; + + if (sourceMegaProduct != null) + { + return ProductArrayMapper.GetMegaProduct(sourceMegaProduct); + } + var product = new Product(); + + if (product.ProductId == null) + { + product.ProductId = enumerator.Current.ProductId; + } + + if (product.Price == default(double)) + { + product.Price = enumerator.Current.Price; + } + + return product; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Product[][i]", + "IEnumerable[i]", + ex); + } + } + + private static MegaProduct GetMegaProduct + ( + MegaProduct sourceMegaProduct + ) + { + try + { + var megaProduct = new MegaProduct(); + + if (megaProduct.HowMega == default(decimal)) + { + megaProduct.HowMega = sourceMegaProduct.HowMega; + } + + if (megaProduct.ProductId == null) + { + megaProduct.ProductId = sourceMegaProduct.ProductId; + } + + if (megaProduct.Price == default(double)) + { + megaProduct.Price = sourceMegaProduct.Price; + } + + return megaProduct; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Product[][i]", + "IEnumerable[i]", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ProductDtoArrayMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ProductDtoArrayMapper.cs new file mode 100644 index 000000000..b6808fb20 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ProductDtoArrayMapper.cs @@ -0,0 +1,236 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class ProductDtoArrayMapper : MappingExecutionContextBase + { + public ProductDtoArrayMapper + ( + ProductDto[] source + ) + : base(source) + { + } + + public ReadOnlyCollection Over + ( + ReadOnlyCollection target + ) + { + return ProductDtoArrayMapper.Overwrite(this.CreateRootMappingData(target)); + } + + private static ReadOnlyCollection Overwrite + ( + IObjectMappingData> pdaToProcData + ) + { + try + { + var collectionData = CollectionData.Create( + pdaToProcData.Source, + pdaToProcData.Target, + pd => pd.ProductId, + p => p.ProductId); + collectionData.Intersection.ForEach( + (existingProductDto, existingProduct, idx) => ProductDtoArrayMapper.GetProduct1(existingProductDto, existingProduct)); + var productDtoIEnumerable = collectionData.NewSourceItems; + var productList = new List(pdaToProcData.Target); + collectionData.AbsentTargetItems.ForEach(p => productList.Remove(p)); + var i = 0; + var enumerator = productDtoIEnumerable.GetEnumerator(); + try + { + while (true) + { + if (!enumerator.MoveNext()) + { + break; + } + + productList.Add(ProductDtoArrayMapper.GetProduct1(enumerator)); + ++i; + } + } + finally + { + enumerator.Dispose(); + } + + return productList.AsReadOnly(); + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ProductDto[]", + "ReadOnlyCollection", + ex); + } + } + + private static Product GetProduct1 + ( + ProductDto existingProductDto, + Product existingProduct + ) + { + try + { + if (existingProductDto == null) + { + return null; + } + + var sourceProductDtoMega = existingProductDto as ProductDtoMega; + + if (sourceProductDtoMega != null) + { + return ProductDtoArrayMapper.GetProduct2(existingProduct, sourceProductDtoMega); + } + + if (existingProduct is MegaProduct) + { + return ProductDtoArrayMapper.GetMegaProduct(existingProduct, existingProductDto); + } + var product = existingProduct ?? new Product(); + product.ProductId = existingProductDto.ProductId; + product.Price = (double)existingProductDto.Price; + + return product; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ProductDto[][i]", + "ReadOnlyCollection[i]", + ex); + } + } + + private static Product GetProduct2 + ( + Product existingProduct, + ProductDtoMega sourceProductDtoMega + ) + { + try + { + var product = existingProduct ?? new Product(); + product.ProductId = sourceProductDtoMega.ProductId; + product.Price = (double)sourceProductDtoMega.Price; + + return product; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ProductDto[][i]", + "ReadOnlyCollection[i]", + ex); + } + } + + private static MegaProduct GetMegaProduct + ( + Product existingProduct, + ProductDto existingProductDto + ) + { + try + { + var megaProduct = ((MegaProduct)existingProduct) ?? new MegaProduct(); + // No data sources for HowMega + megaProduct.ProductId = existingProductDto.ProductId; + megaProduct.Price = (double)existingProductDto.Price; + + return megaProduct; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ProductDto[][i]", + "ReadOnlyCollection[i]", + ex); + } + } + + private static Product GetProduct1 + ( + IEnumerator enumerator + ) + { + try + { + if (enumerator.Current == null) + { + return null; + } + + var sourceProductDtoMega = enumerator.Current as ProductDtoMega; + + if (sourceProductDtoMega != null) + { + return ProductDtoArrayMapper.GetProduct2(sourceProductDtoMega); + } + var product = new Product(); + product.ProductId = enumerator.Current.ProductId; + product.Price = (double)enumerator.Current.Price; + + return product; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ProductDto[][i]", + "ReadOnlyCollection[i]", + ex); + } + } + + private static Product GetProduct2 + ( + ProductDtoMega sourceProductDtoMega + ) + { + try + { + var product = new Product(); + product.ProductId = sourceProductDtoMega.ProductId; + product.Price = (double)sourceProductDtoMega.Price; + + return product; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ProductDto[][i]", + "ReadOnlyCollection[i]", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ProductDtoListMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ProductDtoListMapper.cs new file mode 100644 index 000000000..e073f7878 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ProductDtoListMapper.cs @@ -0,0 +1,129 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class ProductDtoListMapper : MappingExecutionContextBase> + { + public ProductDtoListMapper + ( + List source + ) + : base(source) + { + } + + public IList ToANew() + where TTarget : IList + { + return ProductDtoListMapper.CreateNew(this.CreateRootMappingData(default(IList))); + } + + private static IList CreateNew + ( + IObjectMappingData, IList> pdlToPdilData + ) + { + try + { + var sourceProductDtoList = pdlToPdilData.Source; + var targetProductDtoList = new List(sourceProductDtoList.Count); + var i = 0; + while (true) + { + if (i == sourceProductDtoList.Count) + { + break; + } + + var sourceProductDto = sourceProductDtoList[i]; + targetProductDtoList.Add(ProductDtoListMapper.GetProductDto(sourceProductDto)); + ++i; + } + + return targetProductDtoList; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "List", + "IList", + ex); + } + } + + private static ProductDto GetProductDto + ( + ProductDto sourceProductDto + ) + { + try + { + if (sourceProductDto == null) + { + return null; + } + + var sourceProductDtoMega = sourceProductDto as ProductDtoMega; + + if (sourceProductDtoMega != null) + { + return ProductDtoListMapper.GetProductDtoMega(sourceProductDtoMega); + } + var productDto = new ProductDto(); + productDto.ProductId = sourceProductDto.ProductId; + productDto.Price = sourceProductDto.Price; + + return productDto; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "List[i]", + "IList[i]", + ex); + } + } + + private static ProductDtoMega GetProductDtoMega + ( + ProductDtoMega sourceProductDtoMega + ) + { + try + { + var productDtoMega = new ProductDtoMega(); + productDtoMega.HowMega = sourceProductDtoMega.HowMega; + productDtoMega.ProductId = sourceProductDtoMega.ProductId; + productDtoMega.Price = sourceProductDtoMega.Price; + + return productDtoMega; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "List[i]", + "IList[i]", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ProductMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ProductMapper.cs new file mode 100644 index 000000000..612590fb8 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/ProductMapper.cs @@ -0,0 +1,106 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; +using AgileObjects.NetStandardPolyfills; +using AgileObjects.ReadableExpressions; +using AgileObjects.ReadableExpressions.Extensions; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class ProductMapper : MappingExecutionContextBase + { + public ProductMapper + ( + Product source + ) + : base(source) + { + } + + public TTarget ToANew() + { + if (typeof(TTarget).IsAssignableTo(typeof(ProductDto))) + { + return (TTarget)((object)ProductMapper.CreateNew(this.CreateRootMappingData(default(ProductDto)))); + } + + throw new NotSupportedException( + "Unable to perform a 'CreateNew' mapping from source type 'Product' to target type '" + typeof(TTarget).GetFriendlyName(null) + "'"); + } + + private static ProductDto CreateNew + ( + IObjectMappingData pToPdData + ) + { + Product sourceProduct; + try + { + sourceProduct = pToPdData.Source; + + var sourceMegaProduct = sourceProduct as MegaProduct; + + if (sourceMegaProduct != null) + { + return ProductMapper.GetProductDtoMega(sourceMegaProduct); + } + var productDto = new ProductDto(); + productDto.ProductId = sourceProduct.ProductId; + productDto.Price = ((sourceProduct.Price >= ((double)-79228162514264337593543950335m)) && + (sourceProduct.Price <= ((double)79228162514264337593543950335m))) + ? (decimal)sourceProduct.Price + : default(decimal); + + return productDto; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Product", + "ProductDto", + ex); + } + } + + private static ProductDtoMega GetProductDtoMega + ( + MegaProduct sourceMegaProduct + ) + { + try + { + var productDtoMega = new ProductDtoMega(); + productDtoMega.HowMega = sourceMegaProduct.HowMega.ToString(); + productDtoMega.ProductId = sourceMegaProduct.ProductId; + productDtoMega.Price = ((sourceMegaProduct.Price >= ((double)-79228162514264337593543950335m)) && + (sourceMegaProduct.Price <= ((double)79228162514264337593543950335m))) + ? (decimal)sourceMegaProduct.Price + : default(decimal); + + return productDtoMega; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "MegaProduct", + "ProductDtoMega", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringCollectionMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringCollectionMapper.cs new file mode 100644 index 000000000..59b82670e --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringCollectionMapper.cs @@ -0,0 +1,63 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class StringCollectionMapper : MappingExecutionContextBase> + { + public StringCollectionMapper + ( + Collection source + ) + : base(source) + { + } + + public List Over + ( + List target + ) + { + return StringCollectionMapper.Overwrite(this.CreateRootMappingData(target)); + } + + private static List Overwrite + ( + IObjectMappingData, List> scToSlData + ) + { + try + { + var sourceStringCollection = scToSlData.Source; + var targetStringList = scToSlData.Target; + targetStringList.Clear(); + targetStringList.AddRange(sourceStringCollection); + + return targetStringList; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "Collection", + "List", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringListMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringListMapper.cs new file mode 100644 index 000000000..f210f24f2 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringListMapper.cs @@ -0,0 +1,80 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class StringListMapper : MappingExecutionContextBase> + { + public StringListMapper + ( + List source + ) + : base(source) + { + } + + public Collection ToANew() + where TTarget : Collection> + { + return StringListMapper.CreateNew(this.CreateRootMappingData(default(Collection))); + } + + private static Collection CreateNew + ( + IObjectMappingData, Collection> slToNbcData + ) + { + try + { + var stringList = slToNbcData.Source; + var nullableByteCollection = new Collection(); + var i = 0; + while (true) + { + if (i == stringList.Count) + { + break; + } + + nullableByteCollection.Add(StringListMapper.GetNullableByte(stringList, i)); + ++i; + } + + return nullableByteCollection; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "List", + "Collection", + ex); + } + } + + private static byte? GetNullableByte + ( + List stringList, + int i + ) + { + byte byteValue; + return byte.TryParse(stringList[i], out byteValue) ? (byte?)byteValue : null; + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringMapper.cs new file mode 100644 index 000000000..92e74fdf4 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringMapper.cs @@ -0,0 +1,130 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; +using AgileObjects.ReadableExpressions; +using AgileObjects.ReadableExpressions.Extensions; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class StringMapper : MappingExecutionContextBase + { + public StringMapper + ( + string source + ) + : base(source) + { + } + + public TTarget ToANew() + { + if (typeof(TTarget) == typeof(Title)) + { + return (TTarget)((object)StringMapper.CreateNew(this.CreateRootMappingData(default(Title)))); + } + + throw new NotSupportedException( + "Unable to perform a 'CreateNew' mapping from source type 'string' to target type '" + typeof(TTarget).GetFriendlyName(null) + "'"); + } + + private static Title CreateNew + ( + IObjectMappingData sToTData + ) + { + try + { + if (sToTData.Source == null) + { + return default(Title); + } + + switch (sToTData.Source.ToUpperInvariant()) + { + case "0": + case "UNKNOWN": + return Title.Unknown; + + case "1": + case "MR": + return Title.Mr; + + case "2": + case "MASTER": + return Title.Master; + + case "3": + case "MS": + return Title.Ms; + + case "4": + case "MISS": + return Title.Miss; + + case "5": + case "MRS": + return Title.Mrs; + + case "6": + case "DR": + return Title.Dr; + + case "7": + case "HON": + return Title.Hon; + + case "8": + case "DUKE": + return Title.Duke; + + case "9": + case "COUNT": + return Title.Count; + + case "10": + case "EARL": + return Title.Earl; + + case "11": + case "VISCOUNT": + return Title.Viscount; + + case "12": + case "LORD": + return Title.Lord; + + case "13": + case "LADY": + return Title.Lady; + + case "14": + case "OTHER": + return Title.Other; + } + + return default(Title); + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "string", + "Title", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringPublicFieldMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringPublicFieldMapper.cs new file mode 100644 index 000000000..f3b5eb6c2 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringPublicFieldMapper.cs @@ -0,0 +1,102 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; +using AgileObjects.NetStandardPolyfills; +using AgileObjects.ReadableExpressions; +using AgileObjects.ReadableExpressions.Extensions; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class StringPublicFieldMapper : MappingExecutionContextBase> + { + public StringPublicFieldMapper + ( + PublicField source + ) + : base(source) + { + } + + public TTarget ToANew() + { + if (typeof(TTarget).IsAssignableTo(typeof(PublicField))) + { + return (TTarget)((object)StringPublicFieldMapper.CreateNew(this.CreateRootMappingData(default(PublicField)))); + } + + if (typeof(TTarget).IsAssignableTo(typeof(PublicProperty))) + { + return (TTarget)((object)StringPublicFieldMapper.CreateNew(this.CreateRootMappingData(default(PublicProperty)))); + } + + throw new NotSupportedException( + "Unable to perform a 'CreateNew' mapping from source type 'PublicField' to target type '" + typeof(TTarget).GetFriendlyName(null) + "'"); + } + + private static PublicField CreateNew + ( + IObjectMappingData, PublicField> spfToIpfData + ) + { + try + { + var intPublicField = new PublicField(); + intPublicField.Value = StringPublicFieldMapper.GetInt(spfToIpfData); + + return intPublicField; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicField", + "PublicField", + ex); + } + } + + private static PublicProperty CreateNew + ( + IObjectMappingData, PublicProperty> spfToSppData + ) + { + try + { + var stringPublicProperty = new PublicProperty(); + stringPublicProperty.Value = spfToSppData.Source.Value; + + return stringPublicProperty; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicField", + "PublicProperty", + ex); + } + } + + private static int GetInt + ( + IObjectMappingData, PublicField> spfToIpfData + ) + { + int intValue; + return int.TryParse(spfToIpfData.Source.Value, out intValue) ? intValue : default(int); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringPublicPropertyMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringPublicPropertyMapper.cs new file mode 100644 index 000000000..db265810d --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringPublicPropertyMapper.cs @@ -0,0 +1,67 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class StringPublicPropertyMapper : MappingExecutionContextBase> + { + public StringPublicPropertyMapper + ( + PublicProperty source + ) + : base(source) + { + } + + public PublicField ToANew() + where TTarget : PublicField + { + return StringPublicPropertyMapper.CreateNew(this.CreateRootMappingData(default(PublicField))); + } + + private static PublicField CreateNew + ( + IObjectMappingData, PublicField> sppToIpfData + ) + { + try + { + var intPublicField = new PublicField(); + intPublicField.Value = StringPublicPropertyMapper.GetInt(sppToIpfData); + + return intPublicField; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicProperty", + "PublicField", + ex); + } + } + + private static int GetInt + ( + IObjectMappingData, PublicField> sppToIpfData + ) + { + int intValue; + return int.TryParse(sppToIpfData.Source.Value, out intValue) ? intValue : default(int); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringStringDictionaryMapper.cs b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringStringDictionaryMapper.cs new file mode 100644 index 000000000..a7ce1675a --- /dev/null +++ b/AgileMapper.Buildable.UnitTests.NetStandard2.Mappers/Mappers/StringStringDictionaryMapper.cs @@ -0,0 +1,119 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Linq; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.Extensions.Internal; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; +using AgileObjects.ReadableExpressions; +using AgileObjects.ReadableExpressions.Extensions; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class StringStringDictionaryMapper : MappingExecutionContextBase> + { + public StringStringDictionaryMapper + ( + Dictionary source + ) + : base(source) + { + } + + public TTarget ToANew() + { + if (typeof(TTarget) == typeof(Address[])) + { + return (TTarget)((object)StringStringDictionaryMapper.CreateNew(this.CreateRootMappingData(default(Address[])))); + } + + throw new NotSupportedException( + "Unable to perform a 'CreateNew' mapping from source type 'Dictionary' to target type '" + typeof(TTarget).GetFriendlyName(null) + "'"); + } + + private static Address[] CreateNew + ( + IObjectMappingData, Address[]> ssdToAaData + ) + { + Dictionary sourceStringStringDictionary; + try + { + sourceStringStringDictionary = ssdToAaData.Source; + + var stringStringDictionary_ValueCollection = sourceStringStringDictionary.Values; + var addressList = new List
(stringStringDictionary_ValueCollection.Count); + var i = 0; + while (true) + { + var targetKey = "[" + i + "]"; + + if (sourceStringStringDictionary.Keys.None(key => key.StartsWith(targetKey, StringComparison.OrdinalIgnoreCase))) + { + break; + } + + addressList.Add(StringStringDictionaryMapper.GetAddress(i, sourceStringStringDictionary)); + ++i; + } + + return addressList.ToArray(); + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Dictionary", + "Address[]", + ex); + } + } + + private static Address GetAddress + ( + int i, + Dictionary sourceStringStringDictionary + ) + { + try + { + var address = new Address(); + var line1Key = "[" + i + "].Line1"; + + if ((line1Key = sourceStringStringDictionary.Keys.FirstOrDefault(key => key.MatchesKey(line1Key, ".", "\\[[0-9]+\\]"))) != null) + { + address.Line1 = sourceStringStringDictionary[line1Key]; + } + var line2Key = "[" + i + "].Line2"; + + if ((line2Key = sourceStringStringDictionary.Keys.FirstOrDefault(key => key.MatchesKey(line2Key, ".", "\\[[0-9]+\\]"))) != null) + { + address.Line2 = sourceStringStringDictionary[line2Key]; + } + + return address; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Dictionary['Target'].[i]", + "Address[][i]", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/AgileMapper.Buildable.UnitTests.csproj b/AgileMapper.Buildable.UnitTests/AgileMapper.Buildable.UnitTests.csproj new file mode 100644 index 000000000..c650a8dd9 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/AgileMapper.Buildable.UnitTests.csproj @@ -0,0 +1,32 @@ + + + + net461 + AgileObjects.AgileMapper.Buildable.UnitTests + AgileObjects.AgileMapper.Buildable.UnitTests + true + + 0649;1701;1702 + full + false + + + + false + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/AgileMapper.Buildable.UnitTests/Configuration/DataSources/WhenBuildingToTargetDataSourceMappers.cs b/AgileMapper.Buildable.UnitTests/Configuration/DataSources/WhenBuildingToTargetDataSourceMappers.cs new file mode 100644 index 000000000..da284f0ec --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Configuration/DataSources/WhenBuildingToTargetDataSourceMappers.cs @@ -0,0 +1,29 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Configuration.DataSources +{ + using AgileMapper.UnitTests.Common; + using AgileMapper.UnitTests.Common.TestClasses; + using Xunit; + using GeneratedMapper = Mappers.Mapper; + + public class WhenBuildingToTargetDataSourceMappers + { + [Fact] + public void ShouldApplyAToTargetDataSource() + { + var source = new ToTargetValueSource + { + Value1 = 123, + Value = new PublicTwoFields + { + Value1 = "456", + Value2 = 789 + } + }; + + var result = GeneratedMapper.Map(source).ToANew>(); + + result.Value1.ShouldBe(456); + result.Value2.ShouldBe(789); + } + } +} diff --git a/AgileMapper.Buildable.UnitTests/Dictionaries/WhenBuildingDictionaryCreateNewMappers.cs b/AgileMapper.Buildable.UnitTests/Dictionaries/WhenBuildingDictionaryCreateNewMappers.cs new file mode 100644 index 000000000..c0dd5588f --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Dictionaries/WhenBuildingDictionaryCreateNewMappers.cs @@ -0,0 +1,28 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Dictionaries +{ + using System.Collections.Generic; + using AgileMapper.UnitTests.Common; + using AgileMapper.UnitTests.Common.TestClasses; + using Xunit; + using GeneratedMapper = Mappers.Mapper; + + public class WhenBuildingDictionaryCreateNewMappers + { + [Fact] + public void ShouldBuildANestedComplexTypeToStringDictionaryMapper() + { + var source = new PublicTwoFields + { + Value1 = 12345, + Value2 = new Address { Line1 = "Line 1!", Line2 = "Line 2!" } + }; + + var result = GeneratedMapper.Map(source).ToANew>(); + + result.ShouldNotBeNull(); + result.ShouldContainKeyAndValue("Value1", "12345"); + result.ShouldContainKeyAndValue("Value2.Line1", "Line 1!"); + result.ShouldContainKeyAndValue("Value2.Line2", "Line 2!"); + } + } +} diff --git a/AgileMapper.Buildable.UnitTests/Dictionaries/WhenBuildingSourceDictionaryEnumerableMappers.cs b/AgileMapper.Buildable.UnitTests/Dictionaries/WhenBuildingSourceDictionaryEnumerableMappers.cs new file mode 100644 index 000000000..460eebb13 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Dictionaries/WhenBuildingSourceDictionaryEnumerableMappers.cs @@ -0,0 +1,42 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Dictionaries +{ + using System.Collections.Generic; + using System.Linq; + using AgileMapper.UnitTests.Common; + using AgileMapper.UnitTests.Common.TestClasses; + using Mappers.Extensions; + using Xunit; + + public class WhenBuildingSourceDictionaryEnumerableMappers + { + [Fact] + public void ShouldBuildAStringDictionaryToAddressArrayMapper() + { + var source = new Dictionary + { + ["[0].Line1"] = "Line 1.1", + ["[0].Line2"] = "Line 1.2", + ["[1].Line1"] = "Line 2.1", + ["[2].Line1"] = "Line 3.1", + ["[2].Line2"] = "Line 3.2", + ["[3].Line2"] = "Line 4.2", + }; + + var result = source.Map().ToANew(); + + result.ShouldNotBeNull(); + result.Length.ShouldBe(4); + result.First().Line1.ShouldBe("Line 1.1"); + result.First().Line2.ShouldBe("Line 1.2"); + + result.Second().Line1.ShouldBe("Line 2.1"); + result.Second().Line2.ShouldBeNull(); + + result.Third().Line1.ShouldBe("Line 3.1"); + result.Third().Line2.ShouldBe("Line 3.2"); + + result.Fourth().Line1.ShouldBeNull(); + result.Fourth().Line2.ShouldBe("Line 4.2"); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/MapperConfiguration/CircularReferenceMapperConfiguration.cs b/AgileMapper.Buildable.UnitTests/MapperConfiguration/CircularReferenceMapperConfiguration.cs new file mode 100644 index 000000000..1da5c942c --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/MapperConfiguration/CircularReferenceMapperConfiguration.cs @@ -0,0 +1,13 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.MapperConfiguration +{ + using AgileMapper.UnitTests.Common.TestClasses; + using Buildable.Configuration; + + public class CircularReferenceMapperConfiguration : BuildableMapperConfiguration + { + protected override void Configure() + { + GetPlanFor().ToANew(); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/MapperConfiguration/ComplexTypeCreateNewMapperConfiguration.cs b/AgileMapper.Buildable.UnitTests/MapperConfiguration/ComplexTypeCreateNewMapperConfiguration.cs new file mode 100644 index 000000000..fb8f04739 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/MapperConfiguration/ComplexTypeCreateNewMapperConfiguration.cs @@ -0,0 +1,16 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.MapperConfiguration +{ + using AgileMapper.UnitTests.Common.TestClasses; + using Buildable.Configuration; + + public class ComplexTypeCreateNewMapperConfiguration : BuildableMapperConfiguration + { + protected override void Configure() + { + GetPlanFor>().ToANew>(); + + GetPlanFor>().ToANew>(); + GetPlanFor>().ToANew>(); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/MapperConfiguration/ComplexTypeDeepCloneMapperConfiguration.cs b/AgileMapper.Buildable.UnitTests/MapperConfiguration/ComplexTypeDeepCloneMapperConfiguration.cs new file mode 100644 index 000000000..dae7577c0 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/MapperConfiguration/ComplexTypeDeepCloneMapperConfiguration.cs @@ -0,0 +1,13 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.MapperConfiguration +{ + using AgileMapper.UnitTests.Common.TestClasses; + using Buildable.Configuration; + + public class ComplexTypeDeepCloneMapperConfiguration : BuildableMapperConfiguration + { + protected override void Configure() + { + GetPlanFor>().ToANew>(); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/MapperConfiguration/ComplexTypeMergeMapperConfiguration.cs b/AgileMapper.Buildable.UnitTests/MapperConfiguration/ComplexTypeMergeMapperConfiguration.cs new file mode 100644 index 000000000..0ead3eae8 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/MapperConfiguration/ComplexTypeMergeMapperConfiguration.cs @@ -0,0 +1,13 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.MapperConfiguration +{ + using AgileMapper.UnitTests.Common.TestClasses; + using Buildable.Configuration; + + public class ComplexTypeMergeMapperConfiguration : BuildableMapperConfiguration + { + protected override void Configure() + { + GetPlanFor
().OnTo
(); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/MapperConfiguration/ComplexTypeOverwriteMapperConfiguration.cs b/AgileMapper.Buildable.UnitTests/MapperConfiguration/ComplexTypeOverwriteMapperConfiguration.cs new file mode 100644 index 000000000..76cb87522 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/MapperConfiguration/ComplexTypeOverwriteMapperConfiguration.cs @@ -0,0 +1,13 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.MapperConfiguration +{ + using AgileMapper.UnitTests.Common.TestClasses; + using Buildable.Configuration; + + public class ComplexTypeOverwriteMapperConfiguration : BuildableMapperConfiguration + { + protected override void Configure() + { + GetPlanFor
().Over
(); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/MapperConfiguration/Configuration/DataSources/ToTargetDataSourceMapperConfiguration.cs b/AgileMapper.Buildable.UnitTests/MapperConfiguration/Configuration/DataSources/ToTargetDataSourceMapperConfiguration.cs new file mode 100644 index 000000000..23730299b --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/MapperConfiguration/Configuration/DataSources/ToTargetDataSourceMapperConfiguration.cs @@ -0,0 +1,16 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.MapperConfiguration.Configuration.DataSources +{ + using AgileMapper.UnitTests.Common.TestClasses; + using Buildable.Configuration; + + public class ToTargetDataSourceMapperConfiguration : BuildableMapperConfiguration + { + protected override void Configure() + { + GetPlansFor>() + .To>(cfg => cfg + .Map(ctx => ctx.Source.Value) + .ToTarget()); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/MapperConfiguration/DerivedTypeMapperConfiguration.cs b/AgileMapper.Buildable.UnitTests/MapperConfiguration/DerivedTypeMapperConfiguration.cs new file mode 100644 index 000000000..1019a0aaa --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/MapperConfiguration/DerivedTypeMapperConfiguration.cs @@ -0,0 +1,14 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.MapperConfiguration +{ + using AgileMapper.UnitTests.Common.TestClasses; + using Buildable.Configuration; + + public class DerivedTypeMapperConfiguration : BuildableMapperConfiguration + { + protected override void Configure() + { + GetPlanFor().ToANew(cfg => cfg + .Map().To()); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/MapperConfiguration/Dictionaries/DictionaryCreateNewMapperConfiguration.cs b/AgileMapper.Buildable.UnitTests/MapperConfiguration/Dictionaries/DictionaryCreateNewMapperConfiguration.cs new file mode 100644 index 000000000..9026e24f8 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/MapperConfiguration/Dictionaries/DictionaryCreateNewMapperConfiguration.cs @@ -0,0 +1,15 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.MapperConfiguration.Dictionaries +{ + using System.Collections.Generic; + using AgileMapper.UnitTests.Common.TestClasses; + using Buildable.Configuration; + + public class DictionaryCreateNewMapperConfiguration : BuildableMapperConfiguration + { + protected override void Configure() + { + GetPlanFor>().ToANew>(); + GetPlanFor>().ToANew(); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/MapperConfiguration/EnumerableCreateNewMapperConfiguration.cs b/AgileMapper.Buildable.UnitTests/MapperConfiguration/EnumerableCreateNewMapperConfiguration.cs new file mode 100644 index 000000000..af929d309 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/MapperConfiguration/EnumerableCreateNewMapperConfiguration.cs @@ -0,0 +1,22 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.MapperConfiguration +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using AgileMapper.UnitTests.Common.TestClasses; + using Buildable.Configuration; + + public class EnumerableCreateNewMapperConfiguration : BuildableMapperConfiguration + { + protected override void Configure() + { + GetPlanFor>().ToANew>(); + + GetPlanFor().ToANew>(); + + GetPlanFor>().ToANew(); + + GetPlanFor>().ToANew>(); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/MapperConfiguration/EnumerableMergeMapperConfiguration.cs b/AgileMapper.Buildable.UnitTests/MapperConfiguration/EnumerableMergeMapperConfiguration.cs new file mode 100644 index 000000000..b3744b79f --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/MapperConfiguration/EnumerableMergeMapperConfiguration.cs @@ -0,0 +1,18 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.MapperConfiguration +{ + using System.Collections.Generic; + using AgileMapper.UnitTests.Common.TestClasses; + using Buildable.Configuration; + + public class EnumerableMergeMapperConfiguration : BuildableMapperConfiguration + { + protected override void Configure() + { + GetPlanFor>().OnTo>(); + + GetPlanFor().OnTo>(); + + GetPlanFor().OnTo>(); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/MapperConfiguration/EnumerableOverwriteMapperConfiguration.cs b/AgileMapper.Buildable.UnitTests/MapperConfiguration/EnumerableOverwriteMapperConfiguration.cs new file mode 100644 index 000000000..17153628e --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/MapperConfiguration/EnumerableOverwriteMapperConfiguration.cs @@ -0,0 +1,19 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.MapperConfiguration +{ + using System.Collections.Generic; + using System.Collections.ObjectModel; + using AgileMapper.UnitTests.Common.TestClasses; + using Buildable.Configuration; + + public class EnumerableOverwriteMapperConfiguration : BuildableMapperConfiguration + { + protected override void Configure() + { + GetPlanFor().Over(); + + GetPlanFor>().Over>(); + + GetPlanFor().Over>(); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/MapperConfiguration/RootEnumMapperConfiguration.cs b/AgileMapper.Buildable.UnitTests/MapperConfiguration/RootEnumMapperConfiguration.cs new file mode 100644 index 000000000..037220e96 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/MapperConfiguration/RootEnumMapperConfiguration.cs @@ -0,0 +1,13 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests.MapperConfiguration +{ + using AgileMapper.UnitTests.Common.TestClasses; + using Buildable.Configuration; + + public class RootEnumMapperConfiguration : BuildableMapperConfiguration + { + protected override void Configure() + { + GetPlanFor().ToANew(); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/AddressAddressPublicTwoFieldsMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/AddressAddressPublicTwoFieldsMapper.cs new file mode 100644 index 000000000..a980cbae6 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/AddressAddressPublicTwoFieldsMapper.cs @@ -0,0 +1,118 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class AddressAddressPublicTwoFieldsMapper : MappingExecutionContextBase<PublicTwoFields<Address, Address>> + { + public AddressAddressPublicTwoFieldsMapper + ( + PublicTwoFields<Address, Address> source + ) + : base(source) + { + } + + public PublicTwoFields<Address, Address> ToANew<TTarget>() + where TTarget : PublicTwoFields<Address, Address> + { + return AddressAddressPublicTwoFieldsMapper.CreateNew(this.CreateRootMappingData(default(PublicTwoFields<Address, Address>))); + } + + private static PublicTwoFields<Address, Address> CreateNew + ( + IObjectMappingData<PublicTwoFields<Address, Address>, PublicTwoFields<Address, Address>> aaptfToAaptfData + ) + { + PublicTwoFields<Address, Address> sourceAddressAddressPublicTwoFields; + try + { + sourceAddressAddressPublicTwoFields = aaptfToAaptfData.Source; + + var addressAddressPublicTwoFields = new PublicTwoFields<Address, Address>(); + + if (sourceAddressAddressPublicTwoFields.Value1 != null) + { + addressAddressPublicTwoFields.Value1 = AddressAddressPublicTwoFieldsMapper.GetAddress1(addressAddressPublicTwoFields, sourceAddressAddressPublicTwoFields); + } + + if (sourceAddressAddressPublicTwoFields.Value2 != null) + { + addressAddressPublicTwoFields.Value2 = AddressAddressPublicTwoFieldsMapper.GetAddress2(addressAddressPublicTwoFields, sourceAddressAddressPublicTwoFields); + } + + return addressAddressPublicTwoFields; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicTwoFields<Address, Address>", + "PublicTwoFields<Address, Address>", + ex); + } + } + + private static Address GetAddress1 + ( + PublicTwoFields<Address, Address> addressAddressPublicTwoFields, + PublicTwoFields<Address, Address> sourceAddressAddressPublicTwoFields + ) + { + try + { + var address = addressAddressPublicTwoFields.Value1 ?? new Address(); + address.Line1 = sourceAddressAddressPublicTwoFields.Value1.Line1; + address.Line2 = sourceAddressAddressPublicTwoFields.Value1.Line2; + + return address; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicTwoFields<Address, Address>.Value1", + "PublicTwoFields<Address, Address>.Value1", + ex); + } + } + + private static Address GetAddress2 + ( + PublicTwoFields<Address, Address> addressAddressPublicTwoFields, + PublicTwoFields<Address, Address> sourceAddressAddressPublicTwoFields + ) + { + try + { + var address = addressAddressPublicTwoFields.Value2 ?? new Address(); + address.Line1 = sourceAddressAddressPublicTwoFields.Value2.Line1; + address.Line2 = sourceAddressAddressPublicTwoFields.Value2.Line2; + + return address; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicTwoFields<Address, Address>.Value2", + "PublicTwoFields<Address, Address>.Value2", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/AddressMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/AddressMapper.cs new file mode 100644 index 000000000..e25279b40 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/AddressMapper.cs @@ -0,0 +1,97 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class AddressMapper : MappingExecutionContextBase<Address> + { + public AddressMapper + ( + Address source + ) + : base(source) + { + } + + public Address OnTo + ( + Address target + ) + { + return AddressMapper.Merge(this.CreateRootMappingData(target)); + } + + public Address Over + ( + Address target + ) + { + return AddressMapper.Overwrite(this.CreateRootMappingData(target)); + } + + private static Address Merge + ( + IObjectMappingData<Address, Address> aToAData + ) + { + try + { + if (aToAData.Target.Line1 == null) + { + aToAData.Target.Line1 = aToAData.Source.Line1; + } + + if (aToAData.Target.Line2 == null) + { + aToAData.Target.Line2 = aToAData.Source.Line2; + } + + return aToAData.Target; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Address", + "Address", + ex); + } + } + + private static Address Overwrite + ( + IObjectMappingData<Address, Address> aToAData + ) + { + try + { + aToAData.Target.Line1 = aToAData.Source.Line1; + aToAData.Target.Line2 = aToAData.Source.Line2; + + return aToAData.Target; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "Address", + "Address", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/CharArrayMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/CharArrayMapper.cs new file mode 100644 index 000000000..f7d8cd8e4 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/CharArrayMapper.cs @@ -0,0 +1,67 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Linq; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.ObjectPopulation; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class CharArrayMapper : MappingExecutionContextBase<char[]> + { + public CharArrayMapper + ( + char[] source + ) + : base(source) + { + } + + public int[] Over + ( + int[] target + ) + { + return CharArrayMapper.Overwrite(this.CreateRootMappingData(target)); + } + + private static int[] Overwrite + ( + IObjectMappingData<char[], int[]> caToIaData + ) + { + try + { + return caToIaData.Source.Project(c => CharArrayMapper.GetInt(c)).ToArray(); + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "char[]", + "int[]", + ex); + } + } + + private static int GetInt + ( + char c + ) + { + int intValue; + return int.TryParse(c.ToString(), out intValue) ? intValue : default(int); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/ChildMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/ChildMapper.cs new file mode 100644 index 000000000..a004986c5 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/ChildMapper.cs @@ -0,0 +1,170 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class ChildMapper : MappingExecutionContextBase<Child> + { + public ChildMapper + ( + Child source + ) + : base(source) + { + } + + public Child ToANew<TTarget>() + where TTarget : Child + { + return ChildMapper.CreateNew(this.CreateRootMappingData(default(Child))); + } + + private static Child MapRepeated + ( + IObjectMappingData<Child, Child> cToCData2 + ) + { + try + { + Child child; + + if (cToCData2.TryGet(cToCData2.Source, out child)) + { + return child; + } + + child = cToCData2.Target ?? new Child(); + cToCData2.Register(cToCData2.Source, child); + child.Name = cToCData2.Source.Name; + + if (cToCData2.Source.EldestParent != null) + { + child.EldestParent = ChildMapper.MapRepeated( + MappingExecutionContextBase<Child>.CreateChildMappingData(cToCData2.Source.EldestParent, child.EldestParent, cToCData2)); + } + + return child; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Child.EldestParent.EldestChild", + "Child.EldestParent.EldestChild", + ex); + } + } + + private static Parent MapRepeated + ( + IObjectMappingData<Parent, Parent> pToPData2 + ) + { + try + { + Parent parent; + + if (pToPData2.TryGet(pToPData2.Source, out parent)) + { + return parent; + } + + parent = pToPData2.Target ?? new Parent(); + pToPData2.Register(pToPData2.Source, parent); + parent.Name = pToPData2.Source.Name; + + if (pToPData2.Source.EldestChild != null) + { + parent.EldestChild = ChildMapper.MapRepeated( + MappingExecutionContextBase<Child>.CreateChildMappingData(pToPData2.Source.EldestChild, parent.EldestChild, pToPData2)); + } + + return parent; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Child.EldestChild.EldestParent", + "Child.EldestParent.EldestChild.EldestParent", + ex); + } + } + + private static Child CreateNew + ( + IObjectMappingData<Child, Child> cToCData + ) + { + Child sourceChild; + try + { + sourceChild = cToCData.Source; + + var child = new Child(); + cToCData.Register(sourceChild, child); + child.Name = sourceChild.Name; + + if (sourceChild.EldestParent != null) + { + child.EldestParent = ChildMapper.GetParent(child, cToCData, sourceChild); + } + + return child; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Child", + "Child", + ex); + } + } + + private static Parent GetParent + ( + Child child, + IObjectMappingData<Child, Child> cToCData, + Child sourceChild + ) + { + try + { + var parent = child.EldestParent ?? new Parent(); + cToCData.Register(sourceChild.EldestParent, parent); + parent.Name = sourceChild.EldestParent.Name; + + if (sourceChild.EldestParent.EldestChild != null) + { + parent.EldestChild = ChildMapper.MapRepeated( + MappingExecutionContextBase<Child>.CreateChildMappingData(sourceChild.EldestParent.EldestChild, parent.EldestChild, cToCData)); + } + + return parent; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Child.EldestParent", + "Child.EldestParent", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/DateTimeHashSetMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/DateTimeHashSetMapper.cs new file mode 100644 index 000000000..a01419066 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/DateTimeHashSetMapper.cs @@ -0,0 +1,85 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.ReadableExpressions; +using AgileObjects.ReadableExpressions.Extensions; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class DateTimeHashSetMapper : MappingExecutionContextBase<HashSet<DateTime>> + { + public DateTimeHashSetMapper + ( + HashSet<DateTime> source + ) + : base(source) + { + } + + public TTarget ToANew<TTarget>() + { + if (typeof(TTarget) == typeof(DateTime[])) + { + return (TTarget)((object)DateTimeHashSetMapper.CreateNew(this.CreateRootMappingData(default(DateTime[])))); + } + + throw new NotSupportedException( + "Unable to perform a 'CreateNew' mapping from source type 'HashSet<DateTime>' to target type '" + typeof(TTarget).GetFriendlyName(null) + "'"); + } + + private static DateTime[] CreateNew + ( + IObjectMappingData<HashSet<DateTime>, DateTime[]> dthsToDtaData + ) + { + try + { + var sourceDateTimeHashSet = dthsToDtaData.Source; + var targetDateTimeList = new List<DateTime>(sourceDateTimeHashSet.Count); + var i = 0; + var enumerator = sourceDateTimeHashSet.GetEnumerator(); + try + { + while (true) + { + if (!enumerator.MoveNext()) + { + break; + } + + targetDateTimeList.Add(enumerator.Current); + ++i; + } + } + finally + { + enumerator.Dispose(); + } + + return targetDateTimeList.ToArray(); + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "HashSet<DateTime>", + "DateTime[]", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/DecimalArrayMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/DecimalArrayMapper.cs new file mode 100644 index 000000000..b5576c953 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/DecimalArrayMapper.cs @@ -0,0 +1,80 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.ObjectPopulation; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class DecimalArrayMapper : MappingExecutionContextBase<decimal[]> + { + public DecimalArrayMapper + ( + decimal[] source + ) + : base(source) + { + } + + public HashSet<double> OnTo + ( + HashSet<double> target + ) + { + return DecimalArrayMapper.Merge(this.CreateRootMappingData(target)); + } + + private static HashSet<double> Merge + ( + IObjectMappingData<decimal[], HashSet<double>> daToDhsData + ) + { + try + { + var sourceDoubleIEnumerable = daToDhsData.Source.Project(d => (double)d).Exclude(daToDhsData.Target); + var targetDoubleHashSet = daToDhsData.Target; + var i = 0; + var enumerator = sourceDoubleIEnumerable.GetEnumerator(); + try + { + while (true) + { + if (!enumerator.MoveNext()) + { + break; + } + + targetDoubleHashSet.Add(enumerator.Current); + ++i; + } + } + finally + { + enumerator.Dispose(); + } + + return targetDoubleHashSet; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "decimal[]", + "HashSet<double>", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/Extensions/MappingExtensions.cs b/AgileMapper.Buildable.UnitTests/Mappers/Extensions/MappingExtensions.cs new file mode 100644 index 000000000..987d137ce --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/Extensions/MappingExtensions.cs @@ -0,0 +1,199 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using AgileObjects.AgileMapper.Buildable.UnitTests.Mappers; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers.Extensions +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public static class MappingExtensions + { + public static AddressAddressPublicTwoFieldsMapper Map + ( + this PublicTwoFields<Address, Address> source + ) + { + return new AddressAddressPublicTwoFieldsMapper(source); + } + + public static PublicTwoFields<Address, Address> DeepClone + ( + this PublicTwoFields<Address, Address> source + ) + { + return new AddressAddressPublicTwoFieldsMapper(source).ToANew<PublicTwoFields<Address, Address>>(); + } + + public static AddressMapper Map + ( + this Address source + ) + { + return new AddressMapper(source); + } + + public static CharArrayMapper Map + ( + this char[] source + ) + { + return new CharArrayMapper(source); + } + + public static ChildMapper Map + ( + this Child source + ) + { + return new ChildMapper(source); + } + + public static Child DeepClone + ( + this Child source + ) + { + return new ChildMapper(source).ToANew<Child>(); + } + + public static DateTimeHashSetMapper Map + ( + this HashSet<DateTime> source + ) + { + return new DateTimeHashSetMapper(source); + } + + public static DecimalArrayMapper Map + ( + this decimal[] source + ) + { + return new DecimalArrayMapper(source); + } + + public static IntAddressPublicTwoFieldsMapper Map + ( + this PublicTwoFields<int, Address> source + ) + { + return new IntAddressPublicTwoFieldsMapper(source); + } + + public static IntArrayMapper Map + ( + this int[] source + ) + { + return new IntArrayMapper(source); + } + + public static IntIEnumerableMapper Map + ( + this IEnumerable<int> source + ) + { + return new IntIEnumerableMapper(source); + } + + public static IntStringIntToTargetValueSourceMapper Map + ( + this ToTargetValueSource<int, string, int> source + ) + { + return new IntStringIntToTargetValueSourceMapper(source); + } + + public static ProductArrayMapper Map + ( + this Product[] source + ) + { + return new ProductArrayMapper(source); + } + + public static ProductDtoArrayMapper Map + ( + this ProductDto[] source + ) + { + return new ProductDtoArrayMapper(source); + } + + public static ProductDtoListMapper Map + ( + this List<ProductDto> source + ) + { + return new ProductDtoListMapper(source); + } + + public static ProductMapper Map + ( + this Product source + ) + { + return new ProductMapper(source); + } + + public static StringCollectionMapper Map + ( + this Collection<string> source + ) + { + return new StringCollectionMapper(source); + } + + public static StringListMapper Map + ( + this List<string> source + ) + { + return new StringListMapper(source); + } + + public static StringMapper Map + ( + this string source + ) + { + return new StringMapper(source); + } + + public static StringPublicFieldMapper Map + ( + this PublicField<string> source + ) + { + return new StringPublicFieldMapper(source); + } + + public static StringPublicPropertyMapper Map + ( + this PublicProperty<string> source + ) + { + return new StringPublicPropertyMapper(source); + } + + public static StringStringDictionaryMapper Map + ( + this Dictionary<string, string> source + ) + { + return new StringStringDictionaryMapper(source); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/IntAddressPublicTwoFieldsMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/IntAddressPublicTwoFieldsMapper.cs new file mode 100644 index 000000000..e028d9ace --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/IntAddressPublicTwoFieldsMapper.cs @@ -0,0 +1,65 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class IntAddressPublicTwoFieldsMapper : MappingExecutionContextBase<PublicTwoFields<int, Address>> + { + public IntAddressPublicTwoFieldsMapper + ( + PublicTwoFields<int, Address> source + ) + : base(source) + { + } + + public Dictionary<string, string> ToANew<TTarget>() + where TTarget : Dictionary<string, string> + { + return IntAddressPublicTwoFieldsMapper.CreateNew(this.CreateRootMappingData(default(Dictionary<string, string>))); + } + + private static Dictionary<string, string> CreateNew + ( + IObjectMappingData<PublicTwoFields<int, Address>, Dictionary<string, string>> iaptfToSsdData + ) + { + try + { + var stringStringDictionary = new Dictionary<string, string>(); + stringStringDictionary["Value1"] = iaptfToSsdData.Source.Value1.ToString(); + + if (iaptfToSsdData.Source.Value2 != null) + { + stringStringDictionary["Value2.Line1"] = iaptfToSsdData.Source.Value2.Line1; + stringStringDictionary["Value2.Line2"] = iaptfToSsdData.Source.Value2.Line2; + } + + return stringStringDictionary; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicTwoFields<int, Address>", + "Dictionary<string, string>", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/IntArrayMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/IntArrayMapper.cs new file mode 100644 index 000000000..496a2e484 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/IntArrayMapper.cs @@ -0,0 +1,70 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class IntArrayMapper : MappingExecutionContextBase<int[]> + { + public IntArrayMapper + ( + int[] source + ) + : base(source) + { + } + + public ReadOnlyCollection<int> ToANew<TTarget>() + where TTarget : ReadOnlyCollection<int> + { + return IntArrayMapper.CreateNew(this.CreateRootMappingData(default(ReadOnlyCollection<int>))); + } + + private static ReadOnlyCollection<int> CreateNew + ( + IObjectMappingData<int[], ReadOnlyCollection<int>> iaToIrocData + ) + { + try + { + var sourceIntArray = iaToIrocData.Source; + var targetIntList = new List<int>(sourceIntArray.Length); + var i = 0; + while (true) + { + if (i == sourceIntArray.Length) + { + break; + } + + targetIntList.Add(sourceIntArray[i]); + ++i; + } + + return targetIntList.AsReadOnly(); + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "int[]", + "ReadOnlyCollection<int>", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/IntIEnumerableMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/IntIEnumerableMapper.cs new file mode 100644 index 000000000..f9fe81aa9 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/IntIEnumerableMapper.cs @@ -0,0 +1,80 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.ObjectPopulation; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class IntIEnumerableMapper : MappingExecutionContextBase<IEnumerable<int>> + { + public IntIEnumerableMapper + ( + IEnumerable<int> source + ) + : base(source) + { + } + + public ICollection<int> OnTo + ( + ICollection<int> target + ) + { + return IntIEnumerableMapper.Merge(this.CreateRootMappingData(target)); + } + + private static ICollection<int> Merge + ( + IObjectMappingData<IEnumerable<int>, ICollection<int>> iieToIicData + ) + { + try + { + var sourceIntIEnumerable = iieToIicData.Source.Exclude(iieToIicData.Target); + ICollection<int> targetIntICollection = iieToIicData.Target.IsReadOnly ? new List<int>(iieToIicData.Target) : iieToIicData.Target; + var i = 0; + var enumerator = sourceIntIEnumerable.GetEnumerator(); + try + { + while (true) + { + if (!enumerator.MoveNext()) + { + break; + } + + targetIntICollection.Add(enumerator.Current); + ++i; + } + } + finally + { + enumerator.Dispose(); + } + + return targetIntICollection; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "IEnumerable<int>", + "ICollection<int>", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/IntStringIntToTargetValueSourceMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/IntStringIntToTargetValueSourceMapper.cs new file mode 100644 index 000000000..ab63e2a18 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/IntStringIntToTargetValueSourceMapper.cs @@ -0,0 +1,218 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class IntStringIntToTargetValueSourceMapper : MappingExecutionContextBase<ToTargetValueSource<int, string, int>> + { + public IntStringIntToTargetValueSourceMapper + ( + ToTargetValueSource<int, string, int> source + ) + : base(source) + { + } + + public PublicTwoFields<int, int> ToANew<TTarget>() + where TTarget : PublicTwoFields<int, int> + { + return IntStringIntToTargetValueSourceMapper.CreateNew(this.CreateRootMappingData(default(PublicTwoFields<int, int>))); + } + + public PublicTwoFields<int, int> Over + ( + PublicTwoFields<int, int> target + ) + { + return IntStringIntToTargetValueSourceMapper.Overwrite(this.CreateRootMappingData(target)); + } + + public PublicTwoFields<int, int> OnTo + ( + PublicTwoFields<int, int> target + ) + { + return IntStringIntToTargetValueSourceMapper.Merge(this.CreateRootMappingData(target)); + } + + private static PublicTwoFields<int, int> CreateNew + ( + IObjectMappingData<ToTargetValueSource<int, string, int>, PublicTwoFields<int, int>> isittvsToIiptfData + ) + { + ToTargetValueSource<int, string, int> sourceIntStringIntToTargetValueSource; + try + { + sourceIntStringIntToTargetValueSource = isittvsToIiptfData.Source; + + var intIntPublicTwoFields = new PublicTwoFields<int, int>(); + intIntPublicTwoFields.Value1 = sourceIntStringIntToTargetValueSource.Value1; + // No data sources for Value2 + + if (sourceIntStringIntToTargetValueSource.Value != null) + { + if (sourceIntStringIntToTargetValueSource.Value != null) + { + intIntPublicTwoFields.Value1 = IntStringIntToTargetValueSourceMapper.GetInt1(sourceIntStringIntToTargetValueSource); + } + + if (sourceIntStringIntToTargetValueSource.Value != null) + { + intIntPublicTwoFields.Value2 = sourceIntStringIntToTargetValueSource.Value.Value2; + } + } + + return intIntPublicTwoFields; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "ToTargetValueSource<int, string, int>", + "PublicTwoFields<int, int>", + ex); + } + } + + private static PublicTwoFields<int, int> Overwrite + ( + IObjectMappingData<ToTargetValueSource<int, string, int>, PublicTwoFields<int, int>> isittvsToIiptfData + ) + { + ToTargetValueSource<int, string, int> sourceIntStringIntToTargetValueSource; + try + { + sourceIntStringIntToTargetValueSource = isittvsToIiptfData.Source; + + isittvsToIiptfData.Target.Value1 = sourceIntStringIntToTargetValueSource.Value1; + // No data sources for Value2 + + if (sourceIntStringIntToTargetValueSource.Value != null) + { + if (sourceIntStringIntToTargetValueSource.Value != null) + { + isittvsToIiptfData.Target.Value1 = IntStringIntToTargetValueSourceMapper.GetInt2(sourceIntStringIntToTargetValueSource); + } + else + { + isittvsToIiptfData.Target.Value1 = default(int); + } + + if (sourceIntStringIntToTargetValueSource.Value != null) + { + isittvsToIiptfData.Target.Value2 = sourceIntStringIntToTargetValueSource.Value.Value2; + } + else + { + isittvsToIiptfData.Target.Value2 = default(int); + } + } + + return isittvsToIiptfData.Target; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ToTargetValueSource<int, string, int>", + "PublicTwoFields<int, int>", + ex); + } + } + + private static PublicTwoFields<int, int> Merge + ( + IObjectMappingData<ToTargetValueSource<int, string, int>, PublicTwoFields<int, int>> isittvsToIiptfData + ) + { + ToTargetValueSource<int, string, int> sourceIntStringIntToTargetValueSource; + try + { + sourceIntStringIntToTargetValueSource = isittvsToIiptfData.Source; + + if (isittvsToIiptfData.Target.Value1 == default(int)) + { + isittvsToIiptfData.Target.Value1 = sourceIntStringIntToTargetValueSource.Value1; + } + + // No data sources for Value2 + + if (sourceIntStringIntToTargetValueSource.Value != null) + { + if (isittvsToIiptfData.Target.Value1 == default(int)) + { + if (sourceIntStringIntToTargetValueSource.Value != null) + { + isittvsToIiptfData.Target.Value1 = IntStringIntToTargetValueSourceMapper.GetInt3(sourceIntStringIntToTargetValueSource); + } + } + + if (isittvsToIiptfData.Target.Value2 == default(int)) + { + if (sourceIntStringIntToTargetValueSource.Value != null) + { + isittvsToIiptfData.Target.Value2 = sourceIntStringIntToTargetValueSource.Value.Value2; + } + } + } + + return isittvsToIiptfData.Target; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "ToTargetValueSource<int, string, int>", + "PublicTwoFields<int, int>", + ex); + } + } + + private static int GetInt1 + ( + ToTargetValueSource<int, string, int> sourceIntStringIntToTargetValueSource + ) + { + int intValue; + return int.TryParse(sourceIntStringIntToTargetValueSource.Value.Value1, out intValue) + ? intValue + : default(int); + } + + private static int GetInt2 + ( + ToTargetValueSource<int, string, int> sourceIntStringIntToTargetValueSource + ) + { + int intValue; + return int.TryParse(sourceIntStringIntToTargetValueSource.Value.Value1, out intValue) + ? intValue + : default(int); + } + + private static int GetInt3 + ( + ToTargetValueSource<int, string, int> sourceIntStringIntToTargetValueSource + ) + { + int intValue; + return int.TryParse(sourceIntStringIntToTargetValueSource.Value.Value1, out intValue) + ? intValue + : default(int); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/Mapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/Mapper.cs new file mode 100644 index 000000000..b029798ae --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/Mapper.cs @@ -0,0 +1,198 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public static class Mapper + { + public static AddressAddressPublicTwoFieldsMapper Map + ( + PublicTwoFields<Address, Address> source + ) + { + return new AddressAddressPublicTwoFieldsMapper(source); + } + + public static PublicTwoFields<Address, Address> DeepClone + ( + PublicTwoFields<Address, Address> source + ) + { + return new AddressAddressPublicTwoFieldsMapper(source).ToANew<PublicTwoFields<Address, Address>>(); + } + + public static AddressMapper Map + ( + Address source + ) + { + return new AddressMapper(source); + } + + public static CharArrayMapper Map + ( + char[] source + ) + { + return new CharArrayMapper(source); + } + + public static ChildMapper Map + ( + Child source + ) + { + return new ChildMapper(source); + } + + public static Child DeepClone + ( + Child source + ) + { + return new ChildMapper(source).ToANew<Child>(); + } + + public static DateTimeHashSetMapper Map + ( + HashSet<DateTime> source + ) + { + return new DateTimeHashSetMapper(source); + } + + public static DecimalArrayMapper Map + ( + decimal[] source + ) + { + return new DecimalArrayMapper(source); + } + + public static IntAddressPublicTwoFieldsMapper Map + ( + PublicTwoFields<int, Address> source + ) + { + return new IntAddressPublicTwoFieldsMapper(source); + } + + public static IntArrayMapper Map + ( + int[] source + ) + { + return new IntArrayMapper(source); + } + + public static IntIEnumerableMapper Map + ( + IEnumerable<int> source + ) + { + return new IntIEnumerableMapper(source); + } + + public static IntStringIntToTargetValueSourceMapper Map + ( + ToTargetValueSource<int, string, int> source + ) + { + return new IntStringIntToTargetValueSourceMapper(source); + } + + public static ProductArrayMapper Map + ( + Product[] source + ) + { + return new ProductArrayMapper(source); + } + + public static ProductDtoArrayMapper Map + ( + ProductDto[] source + ) + { + return new ProductDtoArrayMapper(source); + } + + public static ProductDtoListMapper Map + ( + List<ProductDto> source + ) + { + return new ProductDtoListMapper(source); + } + + public static ProductMapper Map + ( + Product source + ) + { + return new ProductMapper(source); + } + + public static StringCollectionMapper Map + ( + Collection<string> source + ) + { + return new StringCollectionMapper(source); + } + + public static StringListMapper Map + ( + List<string> source + ) + { + return new StringListMapper(source); + } + + public static StringMapper Map + ( + string source + ) + { + return new StringMapper(source); + } + + public static StringPublicFieldMapper Map + ( + PublicField<string> source + ) + { + return new StringPublicFieldMapper(source); + } + + public static StringPublicPropertyMapper Map + ( + PublicProperty<string> source + ) + { + return new StringPublicPropertyMapper(source); + } + + public static StringStringDictionaryMapper Map + ( + Dictionary<string, string> source + ) + { + return new StringStringDictionaryMapper(source); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/ProductArrayMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/ProductArrayMapper.cs new file mode 100644 index 000000000..faba24256 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/ProductArrayMapper.cs @@ -0,0 +1,291 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class ProductArrayMapper : MappingExecutionContextBase<Product[]> + { + public ProductArrayMapper + ( + Product[] source + ) + : base(source) + { + } + + public IEnumerable<Product> OnTo + ( + IEnumerable<Product> target + ) + { + return ProductArrayMapper.Merge(this.CreateRootMappingData(target)); + } + + private static IEnumerable<Product> Merge + ( + IObjectMappingData<Product[], IEnumerable<Product>> paToPieData + ) + { + try + { + var collectionData = CollectionData.Create(paToPieData.Source, paToPieData.Target, p => p.ProductId); + collectionData.Intersection.ForEach( + (existingSourceProduct, existingTargetProduct, idx) => ProductArrayMapper.GetProduct1(existingSourceProduct, existingTargetProduct)); + var sourceProductIEnumerable = collectionData.NewSourceItems; + var targetProductICollection = ProductArrayMapper.GetProductICollection(paToPieData); + var i = 0; + var enumerator = sourceProductIEnumerable.GetEnumerator(); + try + { + while (true) + { + if (!enumerator.MoveNext()) + { + break; + } + + targetProductICollection.Add(ProductArrayMapper.GetProduct2(enumerator)); + ++i; + } + } + finally + { + enumerator.Dispose(); + } + + return targetProductICollection; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Product[]", + "IEnumerable<Product>", + ex); + } + } + + private static Product GetProduct1 + ( + Product existingSourceProduct, + Product existingTargetProduct + ) + { + try + { + if (existingSourceProduct == null) + { + return null; + } + + var sourceMegaProduct = existingSourceProduct as MegaProduct; + + if ((sourceMegaProduct != null) && ((existingTargetProduct == null) || (existingTargetProduct is MegaProduct))) + { + return ProductArrayMapper.GetMegaProduct1(existingTargetProduct, sourceMegaProduct); + } + + if (existingTargetProduct is MegaProduct) + { + return ProductArrayMapper.GetMegaProduct2(existingTargetProduct, existingSourceProduct); + } + var product = existingTargetProduct ?? new Product(); + + if (product.ProductId == null) + { + product.ProductId = existingSourceProduct.ProductId; + } + + if (product.Price == default(double)) + { + product.Price = existingSourceProduct.Price; + } + + return product; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Product[][i]", + "IEnumerable<Product>[i]", + ex); + } + } + + private static MegaProduct GetMegaProduct1 + ( + Product existingTargetProduct, + MegaProduct sourceMegaProduct + ) + { + try + { + var megaProduct = ((MegaProduct)existingTargetProduct) ?? new MegaProduct(); + + if (megaProduct.HowMega == default(decimal)) + { + megaProduct.HowMega = sourceMegaProduct.HowMega; + } + + if (megaProduct.ProductId == null) + { + megaProduct.ProductId = sourceMegaProduct.ProductId; + } + + if (megaProduct.Price == default(double)) + { + megaProduct.Price = sourceMegaProduct.Price; + } + + return megaProduct; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Product[][i]", + "IEnumerable<Product>[i]", + ex); + } + } + + private static MegaProduct GetMegaProduct2 + ( + Product existingTargetProduct, + Product existingSourceProduct + ) + { + try + { + var megaProduct = ((MegaProduct)existingTargetProduct) ?? new MegaProduct(); + // No data sources for HowMega + + if (megaProduct.ProductId == null) + { + megaProduct.ProductId = existingSourceProduct.ProductId; + } + + if (megaProduct.Price == default(double)) + { + megaProduct.Price = existingSourceProduct.Price; + } + + return megaProduct; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Product[][i]", + "IEnumerable<Product>[i]", + ex); + } + } + + private static ICollection<Product> GetProductICollection + ( + IObjectMappingData<Product[], IEnumerable<Product>> paToPieData + ) + { + ICollection<Product> collection; + return ((collection = paToPieData.Target as ICollection<Product>) != null) + ? collection.IsReadOnly ? new List<Product>(paToPieData.Target) : collection + : new List<Product>(paToPieData.Target); + } + + private static Product GetProduct2 + ( + IEnumerator<Product> enumerator + ) + { + try + { + if (enumerator.Current == null) + { + return null; + } + + var sourceMegaProduct = enumerator.Current as MegaProduct; + + if (sourceMegaProduct != null) + { + return ProductArrayMapper.GetMegaProduct(sourceMegaProduct); + } + var product = new Product(); + + if (product.ProductId == null) + { + product.ProductId = enumerator.Current.ProductId; + } + + if (product.Price == default(double)) + { + product.Price = enumerator.Current.Price; + } + + return product; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Product[][i]", + "IEnumerable<Product>[i]", + ex); + } + } + + private static MegaProduct GetMegaProduct + ( + MegaProduct sourceMegaProduct + ) + { + try + { + var megaProduct = new MegaProduct(); + + if (megaProduct.HowMega == default(decimal)) + { + megaProduct.HowMega = sourceMegaProduct.HowMega; + } + + if (megaProduct.ProductId == null) + { + megaProduct.ProductId = sourceMegaProduct.ProductId; + } + + if (megaProduct.Price == default(double)) + { + megaProduct.Price = sourceMegaProduct.Price; + } + + return megaProduct; + } + catch (Exception ex) + { + throw MappingException.For( + "Merge", + "Product[][i]", + "IEnumerable<Product>[i]", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/ProductDtoArrayMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/ProductDtoArrayMapper.cs new file mode 100644 index 000000000..b6808fb20 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/ProductDtoArrayMapper.cs @@ -0,0 +1,236 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class ProductDtoArrayMapper : MappingExecutionContextBase<ProductDto[]> + { + public ProductDtoArrayMapper + ( + ProductDto[] source + ) + : base(source) + { + } + + public ReadOnlyCollection<Product> Over + ( + ReadOnlyCollection<Product> target + ) + { + return ProductDtoArrayMapper.Overwrite(this.CreateRootMappingData(target)); + } + + private static ReadOnlyCollection<Product> Overwrite + ( + IObjectMappingData<ProductDto[], ReadOnlyCollection<Product>> pdaToProcData + ) + { + try + { + var collectionData = CollectionData.Create( + pdaToProcData.Source, + pdaToProcData.Target, + pd => pd.ProductId, + p => p.ProductId); + collectionData.Intersection.ForEach( + (existingProductDto, existingProduct, idx) => ProductDtoArrayMapper.GetProduct1(existingProductDto, existingProduct)); + var productDtoIEnumerable = collectionData.NewSourceItems; + var productList = new List<Product>(pdaToProcData.Target); + collectionData.AbsentTargetItems.ForEach(p => productList.Remove(p)); + var i = 0; + var enumerator = productDtoIEnumerable.GetEnumerator(); + try + { + while (true) + { + if (!enumerator.MoveNext()) + { + break; + } + + productList.Add(ProductDtoArrayMapper.GetProduct1(enumerator)); + ++i; + } + } + finally + { + enumerator.Dispose(); + } + + return productList.AsReadOnly(); + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ProductDto[]", + "ReadOnlyCollection<Product>", + ex); + } + } + + private static Product GetProduct1 + ( + ProductDto existingProductDto, + Product existingProduct + ) + { + try + { + if (existingProductDto == null) + { + return null; + } + + var sourceProductDtoMega = existingProductDto as ProductDtoMega; + + if (sourceProductDtoMega != null) + { + return ProductDtoArrayMapper.GetProduct2(existingProduct, sourceProductDtoMega); + } + + if (existingProduct is MegaProduct) + { + return ProductDtoArrayMapper.GetMegaProduct(existingProduct, existingProductDto); + } + var product = existingProduct ?? new Product(); + product.ProductId = existingProductDto.ProductId; + product.Price = (double)existingProductDto.Price; + + return product; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ProductDto[][i]", + "ReadOnlyCollection<Product>[i]", + ex); + } + } + + private static Product GetProduct2 + ( + Product existingProduct, + ProductDtoMega sourceProductDtoMega + ) + { + try + { + var product = existingProduct ?? new Product(); + product.ProductId = sourceProductDtoMega.ProductId; + product.Price = (double)sourceProductDtoMega.Price; + + return product; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ProductDto[][i]", + "ReadOnlyCollection<Product>[i]", + ex); + } + } + + private static MegaProduct GetMegaProduct + ( + Product existingProduct, + ProductDto existingProductDto + ) + { + try + { + var megaProduct = ((MegaProduct)existingProduct) ?? new MegaProduct(); + // No data sources for HowMega + megaProduct.ProductId = existingProductDto.ProductId; + megaProduct.Price = (double)existingProductDto.Price; + + return megaProduct; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ProductDto[][i]", + "ReadOnlyCollection<Product>[i]", + ex); + } + } + + private static Product GetProduct1 + ( + IEnumerator<ProductDto> enumerator + ) + { + try + { + if (enumerator.Current == null) + { + return null; + } + + var sourceProductDtoMega = enumerator.Current as ProductDtoMega; + + if (sourceProductDtoMega != null) + { + return ProductDtoArrayMapper.GetProduct2(sourceProductDtoMega); + } + var product = new Product(); + product.ProductId = enumerator.Current.ProductId; + product.Price = (double)enumerator.Current.Price; + + return product; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ProductDto[][i]", + "ReadOnlyCollection<Product>[i]", + ex); + } + } + + private static Product GetProduct2 + ( + ProductDtoMega sourceProductDtoMega + ) + { + try + { + var product = new Product(); + product.ProductId = sourceProductDtoMega.ProductId; + product.Price = (double)sourceProductDtoMega.Price; + + return product; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "ProductDto[][i]", + "ReadOnlyCollection<Product>[i]", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/ProductDtoListMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/ProductDtoListMapper.cs new file mode 100644 index 000000000..e073f7878 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/ProductDtoListMapper.cs @@ -0,0 +1,129 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class ProductDtoListMapper : MappingExecutionContextBase<List<ProductDto>> + { + public ProductDtoListMapper + ( + List<ProductDto> source + ) + : base(source) + { + } + + public IList<ProductDto> ToANew<TTarget>() + where TTarget : IList<ProductDto> + { + return ProductDtoListMapper.CreateNew(this.CreateRootMappingData(default(IList<ProductDto>))); + } + + private static IList<ProductDto> CreateNew + ( + IObjectMappingData<List<ProductDto>, IList<ProductDto>> pdlToPdilData + ) + { + try + { + var sourceProductDtoList = pdlToPdilData.Source; + var targetProductDtoList = new List<ProductDto>(sourceProductDtoList.Count); + var i = 0; + while (true) + { + if (i == sourceProductDtoList.Count) + { + break; + } + + var sourceProductDto = sourceProductDtoList[i]; + targetProductDtoList.Add(ProductDtoListMapper.GetProductDto(sourceProductDto)); + ++i; + } + + return targetProductDtoList; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "List<ProductDto>", + "IList<ProductDto>", + ex); + } + } + + private static ProductDto GetProductDto + ( + ProductDto sourceProductDto + ) + { + try + { + if (sourceProductDto == null) + { + return null; + } + + var sourceProductDtoMega = sourceProductDto as ProductDtoMega; + + if (sourceProductDtoMega != null) + { + return ProductDtoListMapper.GetProductDtoMega(sourceProductDtoMega); + } + var productDto = new ProductDto(); + productDto.ProductId = sourceProductDto.ProductId; + productDto.Price = sourceProductDto.Price; + + return productDto; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "List<ProductDto>[i]", + "IList<ProductDto>[i]", + ex); + } + } + + private static ProductDtoMega GetProductDtoMega + ( + ProductDtoMega sourceProductDtoMega + ) + { + try + { + var productDtoMega = new ProductDtoMega(); + productDtoMega.HowMega = sourceProductDtoMega.HowMega; + productDtoMega.ProductId = sourceProductDtoMega.ProductId; + productDtoMega.Price = sourceProductDtoMega.Price; + + return productDtoMega; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "List<ProductDto>[i]", + "IList<ProductDto>[i]", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/ProductMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/ProductMapper.cs new file mode 100644 index 000000000..612590fb8 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/ProductMapper.cs @@ -0,0 +1,106 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; +using AgileObjects.NetStandardPolyfills; +using AgileObjects.ReadableExpressions; +using AgileObjects.ReadableExpressions.Extensions; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class ProductMapper : MappingExecutionContextBase<Product> + { + public ProductMapper + ( + Product source + ) + : base(source) + { + } + + public TTarget ToANew<TTarget>() + { + if (typeof(TTarget).IsAssignableTo(typeof(ProductDto))) + { + return (TTarget)((object)ProductMapper.CreateNew(this.CreateRootMappingData(default(ProductDto)))); + } + + throw new NotSupportedException( + "Unable to perform a 'CreateNew' mapping from source type 'Product' to target type '" + typeof(TTarget).GetFriendlyName(null) + "'"); + } + + private static ProductDto CreateNew + ( + IObjectMappingData<Product, ProductDto> pToPdData + ) + { + Product sourceProduct; + try + { + sourceProduct = pToPdData.Source; + + var sourceMegaProduct = sourceProduct as MegaProduct; + + if (sourceMegaProduct != null) + { + return ProductMapper.GetProductDtoMega(sourceMegaProduct); + } + var productDto = new ProductDto(); + productDto.ProductId = sourceProduct.ProductId; + productDto.Price = ((sourceProduct.Price >= ((double)-79228162514264337593543950335m)) && + (sourceProduct.Price <= ((double)79228162514264337593543950335m))) + ? (decimal)sourceProduct.Price + : default(decimal); + + return productDto; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Product", + "ProductDto", + ex); + } + } + + private static ProductDtoMega GetProductDtoMega + ( + MegaProduct sourceMegaProduct + ) + { + try + { + var productDtoMega = new ProductDtoMega(); + productDtoMega.HowMega = sourceMegaProduct.HowMega.ToString(); + productDtoMega.ProductId = sourceMegaProduct.ProductId; + productDtoMega.Price = ((sourceMegaProduct.Price >= ((double)-79228162514264337593543950335m)) && + (sourceMegaProduct.Price <= ((double)79228162514264337593543950335m))) + ? (decimal)sourceMegaProduct.Price + : default(decimal); + + return productDtoMega; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "MegaProduct", + "ProductDtoMega", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/StringCollectionMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/StringCollectionMapper.cs new file mode 100644 index 000000000..59b82670e --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/StringCollectionMapper.cs @@ -0,0 +1,63 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class StringCollectionMapper : MappingExecutionContextBase<Collection<string>> + { + public StringCollectionMapper + ( + Collection<string> source + ) + : base(source) + { + } + + public List<string> Over + ( + List<string> target + ) + { + return StringCollectionMapper.Overwrite(this.CreateRootMappingData(target)); + } + + private static List<string> Overwrite + ( + IObjectMappingData<Collection<string>, List<string>> scToSlData + ) + { + try + { + var sourceStringCollection = scToSlData.Source; + var targetStringList = scToSlData.Target; + targetStringList.Clear(); + targetStringList.AddRange(sourceStringCollection); + + return targetStringList; + } + catch (Exception ex) + { + throw MappingException.For( + "Overwrite", + "Collection<string>", + "List<string>", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/StringListMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/StringListMapper.cs new file mode 100644 index 000000000..f210f24f2 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/StringListMapper.cs @@ -0,0 +1,80 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class StringListMapper : MappingExecutionContextBase<List<string>> + { + public StringListMapper + ( + List<string> source + ) + : base(source) + { + } + + public Collection<byte?> ToANew<TTarget>() + where TTarget : Collection<Nullable<byte>> + { + return StringListMapper.CreateNew(this.CreateRootMappingData(default(Collection<byte?>))); + } + + private static Collection<byte?> CreateNew + ( + IObjectMappingData<List<string>, Collection<byte?>> slToNbcData + ) + { + try + { + var stringList = slToNbcData.Source; + var nullableByteCollection = new Collection<byte?>(); + var i = 0; + while (true) + { + if (i == stringList.Count) + { + break; + } + + nullableByteCollection.Add(StringListMapper.GetNullableByte(stringList, i)); + ++i; + } + + return nullableByteCollection; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "List<string>", + "Collection<byte?>", + ex); + } + } + + private static byte? GetNullableByte + ( + List<string> stringList, + int i + ) + { + byte byteValue; + return byte.TryParse(stringList[i], out byteValue) ? (byte?)byteValue : null; + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/StringMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/StringMapper.cs new file mode 100644 index 000000000..92e74fdf4 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/StringMapper.cs @@ -0,0 +1,130 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; +using AgileObjects.ReadableExpressions; +using AgileObjects.ReadableExpressions.Extensions; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class StringMapper : MappingExecutionContextBase<string> + { + public StringMapper + ( + string source + ) + : base(source) + { + } + + public TTarget ToANew<TTarget>() + { + if (typeof(TTarget) == typeof(Title)) + { + return (TTarget)((object)StringMapper.CreateNew(this.CreateRootMappingData(default(Title)))); + } + + throw new NotSupportedException( + "Unable to perform a 'CreateNew' mapping from source type 'string' to target type '" + typeof(TTarget).GetFriendlyName(null) + "'"); + } + + private static Title CreateNew + ( + IObjectMappingData<string, Title> sToTData + ) + { + try + { + if (sToTData.Source == null) + { + return default(Title); + } + + switch (sToTData.Source.ToUpperInvariant()) + { + case "0": + case "UNKNOWN": + return Title.Unknown; + + case "1": + case "MR": + return Title.Mr; + + case "2": + case "MASTER": + return Title.Master; + + case "3": + case "MS": + return Title.Ms; + + case "4": + case "MISS": + return Title.Miss; + + case "5": + case "MRS": + return Title.Mrs; + + case "6": + case "DR": + return Title.Dr; + + case "7": + case "HON": + return Title.Hon; + + case "8": + case "DUKE": + return Title.Duke; + + case "9": + case "COUNT": + return Title.Count; + + case "10": + case "EARL": + return Title.Earl; + + case "11": + case "VISCOUNT": + return Title.Viscount; + + case "12": + case "LORD": + return Title.Lord; + + case "13": + case "LADY": + return Title.Lady; + + case "14": + case "OTHER": + return Title.Other; + } + + return default(Title); + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "string", + "Title", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/StringPublicFieldMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/StringPublicFieldMapper.cs new file mode 100644 index 000000000..f3b5eb6c2 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/StringPublicFieldMapper.cs @@ -0,0 +1,102 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; +using AgileObjects.NetStandardPolyfills; +using AgileObjects.ReadableExpressions; +using AgileObjects.ReadableExpressions.Extensions; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class StringPublicFieldMapper : MappingExecutionContextBase<PublicField<string>> + { + public StringPublicFieldMapper + ( + PublicField<string> source + ) + : base(source) + { + } + + public TTarget ToANew<TTarget>() + { + if (typeof(TTarget).IsAssignableTo(typeof(PublicField<int>))) + { + return (TTarget)((object)StringPublicFieldMapper.CreateNew(this.CreateRootMappingData(default(PublicField<int>)))); + } + + if (typeof(TTarget).IsAssignableTo(typeof(PublicProperty<string>))) + { + return (TTarget)((object)StringPublicFieldMapper.CreateNew(this.CreateRootMappingData(default(PublicProperty<string>)))); + } + + throw new NotSupportedException( + "Unable to perform a 'CreateNew' mapping from source type 'PublicField<string>' to target type '" + typeof(TTarget).GetFriendlyName(null) + "'"); + } + + private static PublicField<int> CreateNew + ( + IObjectMappingData<PublicField<string>, PublicField<int>> spfToIpfData + ) + { + try + { + var intPublicField = new PublicField<int>(); + intPublicField.Value = StringPublicFieldMapper.GetInt(spfToIpfData); + + return intPublicField; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicField<string>", + "PublicField<int>", + ex); + } + } + + private static PublicProperty<string> CreateNew + ( + IObjectMappingData<PublicField<string>, PublicProperty<string>> spfToSppData + ) + { + try + { + var stringPublicProperty = new PublicProperty<string>(); + stringPublicProperty.Value = spfToSppData.Source.Value; + + return stringPublicProperty; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicField<string>", + "PublicProperty<string>", + ex); + } + } + + private static int GetInt + ( + IObjectMappingData<PublicField<string>, PublicField<int>> spfToIpfData + ) + { + int intValue; + return int.TryParse(spfToIpfData.Source.Value, out intValue) ? intValue : default(int); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/StringPublicPropertyMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/StringPublicPropertyMapper.cs new file mode 100644 index 000000000..db265810d --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/StringPublicPropertyMapper.cs @@ -0,0 +1,67 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class StringPublicPropertyMapper : MappingExecutionContextBase<PublicProperty<string>> + { + public StringPublicPropertyMapper + ( + PublicProperty<string> source + ) + : base(source) + { + } + + public PublicField<int> ToANew<TTarget>() + where TTarget : PublicField<int> + { + return StringPublicPropertyMapper.CreateNew(this.CreateRootMappingData(default(PublicField<int>))); + } + + private static PublicField<int> CreateNew + ( + IObjectMappingData<PublicProperty<string>, PublicField<int>> sppToIpfData + ) + { + try + { + var intPublicField = new PublicField<int>(); + intPublicField.Value = StringPublicPropertyMapper.GetInt(sppToIpfData); + + return intPublicField; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "PublicProperty<string>", + "PublicField<int>", + ex); + } + } + + private static int GetInt + ( + IObjectMappingData<PublicProperty<string>, PublicField<int>> sppToIpfData + ) + { + int intValue; + return int.TryParse(sppToIpfData.Source.Value, out intValue) ? intValue : default(int); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/Mappers/StringStringDictionaryMapper.cs b/AgileMapper.Buildable.UnitTests/Mappers/StringStringDictionaryMapper.cs new file mode 100644 index 000000000..a7ce1675a --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/Mappers/StringStringDictionaryMapper.cs @@ -0,0 +1,119 @@ +// ------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by AgileObjects.AgileMapper.Buildable. +// Runtime Version: 0.1.0.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +// ------------------------------------------------------------------------------ + +using System; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Linq; +using AgileObjects.AgileMapper; +using AgileObjects.AgileMapper.Extensions; +using AgileObjects.AgileMapper.Extensions.Internal; +using AgileObjects.AgileMapper.ObjectPopulation; +using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; +using AgileObjects.ReadableExpressions; +using AgileObjects.ReadableExpressions.Extensions; + +namespace AgileObjects.AgileMapper.Buildable.UnitTests.Mappers +{ + [GeneratedCode("AgileObjects.AgileMapper.Buildable", "0.1.0.0")] + public class StringStringDictionaryMapper : MappingExecutionContextBase<Dictionary<string, string>> + { + public StringStringDictionaryMapper + ( + Dictionary<string, string> source + ) + : base(source) + { + } + + public TTarget ToANew<TTarget>() + { + if (typeof(TTarget) == typeof(Address[])) + { + return (TTarget)((object)StringStringDictionaryMapper.CreateNew(this.CreateRootMappingData(default(Address[])))); + } + + throw new NotSupportedException( + "Unable to perform a 'CreateNew' mapping from source type 'Dictionary<string, string>' to target type '" + typeof(TTarget).GetFriendlyName(null) + "'"); + } + + private static Address[] CreateNew + ( + IObjectMappingData<Dictionary<string, string>, Address[]> ssdToAaData + ) + { + Dictionary<string, string> sourceStringStringDictionary; + try + { + sourceStringStringDictionary = ssdToAaData.Source; + + var stringStringDictionary_ValueCollection = sourceStringStringDictionary.Values; + var addressList = new List<Address>(stringStringDictionary_ValueCollection.Count); + var i = 0; + while (true) + { + var targetKey = "[" + i + "]"; + + if (sourceStringStringDictionary.Keys.None(key => key.StartsWith(targetKey, StringComparison.OrdinalIgnoreCase))) + { + break; + } + + addressList.Add(StringStringDictionaryMapper.GetAddress(i, sourceStringStringDictionary)); + ++i; + } + + return addressList.ToArray(); + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Dictionary<string, string>", + "Address[]", + ex); + } + } + + private static Address GetAddress + ( + int i, + Dictionary<string, string> sourceStringStringDictionary + ) + { + try + { + var address = new Address(); + var line1Key = "[" + i + "].Line1"; + + if ((line1Key = sourceStringStringDictionary.Keys.FirstOrDefault(key => key.MatchesKey(line1Key, ".", "\\[[0-9]+\\]"))) != null) + { + address.Line1 = sourceStringStringDictionary[line1Key]; + } + var line2Key = "[" + i + "].Line2"; + + if ((line2Key = sourceStringStringDictionary.Keys.FirstOrDefault(key => key.MatchesKey(line2Key, ".", "\\[[0-9]+\\]"))) != null) + { + address.Line2 = sourceStringStringDictionary[line2Key]; + } + + return address; + } + catch (Exception ex) + { + throw MappingException.For( + "CreateNew", + "Dictionary<string, string>['Target'].[i]", + "Address[][i]", + ex); + } + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/WhenBuildingCircularReferenceMappers.cs b/AgileMapper.Buildable.UnitTests/WhenBuildingCircularReferenceMappers.cs new file mode 100644 index 000000000..1d880eedb --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/WhenBuildingCircularReferenceMappers.cs @@ -0,0 +1,49 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests +{ + using AgileMapper.UnitTests.Common; + using AgileMapper.UnitTests.Common.TestClasses; + using Xunit; + using GeneratedMapper = Mappers.Mapper; + + public class WhenBuildingCircularReferenceMappers + { + [Fact] + public void ShouldBuildACircularReferenceMapper() + { + var source = new Child + { + Name = "Fred", + EldestParent = new Parent + { + Name = "Bonnie", + EldestChild = new Child + { + Name = "Samson", + EldestParent = new Parent + { + Name = "Franklin" + } + } + } + }; + + source.EldestParent.EldestChild.EldestParent.EldestChild = source; + + var result = GeneratedMapper.Map(source).ToANew<Child>(); + + result.ShouldNotBeNull().ShouldNotBeSameAs(source); + + result.Name.ShouldBe("Fred"); + result.EldestParent.ShouldNotBeNull(); + + result.EldestParent.Name.ShouldBe("Bonnie"); + result.EldestParent.EldestChild.ShouldNotBeNull(); + + result.EldestParent.EldestChild.Name.ShouldBe("Samson"); + result.EldestParent.EldestChild.EldestParent.ShouldNotBeNull(); + + result.EldestParent.EldestChild.EldestParent.Name.ShouldBe("Franklin"); + result.EldestParent.EldestChild.EldestParent.EldestChild.ShouldBeSameAs(result); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/WhenBuildingComplexTypeCreateNewMappers.cs b/AgileMapper.Buildable.UnitTests/WhenBuildingComplexTypeCreateNewMappers.cs new file mode 100644 index 000000000..539759b2c --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/WhenBuildingComplexTypeCreateNewMappers.cs @@ -0,0 +1,61 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests +{ + using System; + using AgileMapper.UnitTests.Common; + using AgileMapper.UnitTests.Common.TestClasses; + using Mappers.Extensions; + using Xunit; + using GeneratedMapper = Mappers.Mapper; + + public class WhenBuildingComplexTypeCreateNewMappers + { + [Fact] + public void ShouldBuildSingleSourceSingleTargetMapper() + { + var source = new PublicProperty<string> { Value = "123" }; + var result = GeneratedMapper.Map(source).ToANew<PublicField<int>>(); + result.Value.ShouldBe(123); + } + + [Fact] + public void ShouldBuildSingleSourceMultipleTargetMapper() + { + var source = new PublicField<string> { Value = "456" }; + var publicFieldResult = GeneratedMapper.Map(source).ToANew<PublicField<int>>(); + publicFieldResult.Value.ShouldBe(456); + + var publicPropertyResult = source.Map().ToANew<PublicProperty<string>>(); + publicPropertyResult.Value.ShouldBe("456"); + + var notSupportedEx = Should.Throw<NotSupportedException>(() => + { + GeneratedMapper.Map(source).ToANew<PublicField<DateTime>>(); + }); + + var notSupportedMessage = notSupportedEx.Message.ShouldNotBeNull(); + + notSupportedMessage.ShouldContain("Unable"); + notSupportedMessage.ShouldContain("CreateNew"); + notSupportedMessage.ShouldContain("source type 'PublicField<string>'"); + notSupportedMessage.ShouldContain("target type 'PublicField<DateTime>'"); + } + + [Fact] + public void ShouldBuildADeepCloneMapper() + { + var source = new PublicTwoFields<Address, Address> + { + Value1 = new Address { Line1 = "Line 1.1" }, + Value2 = new Address { Line2 = "Line 2.2" } + }; + + var result = source.DeepClone(); + + result.ShouldNotBeSameAs(source); + result.Value1.Line1.ShouldBe("Line 1.1"); + result.Value1.Line2.ShouldBeNull(); + result.Value2.Line1.ShouldBeNull(); + result.Value2.Line2.ShouldBe("Line 2.2"); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/WhenBuildingComplexTypeMergeMappers.cs b/AgileMapper.Buildable.UnitTests/WhenBuildingComplexTypeMergeMappers.cs new file mode 100644 index 000000000..ade0d1641 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/WhenBuildingComplexTypeMergeMappers.cs @@ -0,0 +1,22 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests +{ + using AgileMapper.UnitTests.Common; + using AgileObjects.AgileMapper.UnitTests.Common.TestClasses; + using Xunit; + using GeneratedMapper = Mappers.Mapper; + + public class WhenBuildingComplexTypeMergeMappers + { + [Fact] + public void ShouldBuildASingleSourceSingleTargetMapper() + { + var source = new Address { Line1 = "Line 1!" }; + var target = new Address { Line2 = "Line 2!" }; + + GeneratedMapper.Map(source).OnTo(target); + + target.Line1.ShouldBe("Line 1!"); + target.Line2.ShouldBe("Line 2!"); + } + } +} diff --git a/AgileMapper.Buildable.UnitTests/WhenBuildingComplexTypeOverwriteMappers.cs b/AgileMapper.Buildable.UnitTests/WhenBuildingComplexTypeOverwriteMappers.cs new file mode 100644 index 000000000..d7453843c --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/WhenBuildingComplexTypeOverwriteMappers.cs @@ -0,0 +1,22 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests +{ + using AgileMapper.UnitTests.Common; + using AgileMapper.UnitTests.Common.TestClasses; + using Xunit; + using GeneratedMapper = Mappers.Mapper; + + public class WhenBuildingComplexTypeOverwriteMappers + { + [Fact] + public void ShouldBuildASingleSourceSingleTargetMapper() + { + var source = new Address { Line1 = "1.1", Line2 = "1.2" }; + var target = new Address { Line1 = "2.1", Line2 = "2.2" }; + + GeneratedMapper.Map(source).Over(target); + + target.Line1.ShouldBe("1.1"); + target.Line2.ShouldBe("1.2"); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable.UnitTests/WhenBuildingDerivedTypeMappers.cs b/AgileMapper.Buildable.UnitTests/WhenBuildingDerivedTypeMappers.cs new file mode 100644 index 000000000..53995ee71 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/WhenBuildingDerivedTypeMappers.cs @@ -0,0 +1,44 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests +{ + using AgileMapper.UnitTests.Common; + using AgileMapper.UnitTests.Common.TestClasses; + using Xunit; + using GeneratedMapper = Mappers.Mapper; + + public class WhenBuildingDerivedTypeMappers + { + [Fact] + public void ShouldBuildADerivedTypeCreateNewMapper() + { + var baseTypeSource = new Product { ProductId = "111", Price = 19.99 }; + var baseTypeResult = GeneratedMapper.Map(baseTypeSource).ToANew<ProductDto>(); + + baseTypeResult.ProductId.ShouldBe("111"); + baseTypeResult.Price.ShouldBe(19.99m); + + var derivedTypeSource = new MegaProduct + { + ProductId = "222", + Price = 119.99, + HowMega = 1.0m + }; + + var derivedTypeToBaseTypeResult = GeneratedMapper + .Map(derivedTypeSource) + .ToANew<ProductDto>() + .ShouldBeOfType<ProductDtoMega>(); + + derivedTypeToBaseTypeResult.ProductId.ShouldBe("222"); + derivedTypeToBaseTypeResult.Price.ShouldBe(119.99m); + derivedTypeToBaseTypeResult.HowMega.ShouldBe("1.0"); + + var derivedTypeToDerivedTypeResult = GeneratedMapper + .Map(derivedTypeSource) + .ToANew<ProductDtoMega>(); + + derivedTypeToDerivedTypeResult.ProductId.ShouldBe("222"); + derivedTypeToDerivedTypeResult.Price.ShouldBe(119.99m); + derivedTypeToDerivedTypeResult.HowMega.ShouldBe("1.0"); + } + } +} diff --git a/AgileMapper.Buildable.UnitTests/WhenBuildingEnumerableCreateNewMappers.cs b/AgileMapper.Buildable.UnitTests/WhenBuildingEnumerableCreateNewMappers.cs new file mode 100644 index 000000000..44f46c0c0 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/WhenBuildingEnumerableCreateNewMappers.cs @@ -0,0 +1,66 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using AgileMapper.UnitTests.Common; + using AgileMapper.UnitTests.Common.TestClasses; + using Xunit; + using GeneratedMapper = Mappers.Mapper; + + public class WhenBuildingEnumerableCreateNewMappers + { + [Fact] + public void ShouldBuildASimpleTypeListToCollectionMapper() + { + var source = new List<string> { "3", "2", "1", "12345" }; + var result = GeneratedMapper.Map(source).ToANew<Collection<byte?>>(); + + result.ShouldNotBeNull(); + result.ShouldBe<byte?>(3, 2, 1, null); + } + + [Fact] + public void ShouldBuildASimpleTypeArrayToReadOnlyCollectionMapper() + { + var source = new[] { 1, 2, 3 }; + var result = GeneratedMapper.Map(source).ToANew<ReadOnlyCollection<int>>(); + + result.ShouldNotBeNull(); + result.ShouldBe(1, 2, 3); + } + + [Fact] + public void ShouldBuildASimpleTypeHashSetToArrayMapper() + { + var today = DateTime.Today; + var tomorrow = today.AddDays(+1); + var yesterday = today.AddDays(-1); + + var source = new HashSet<DateTime> { yesterday, today, tomorrow }; + var result = GeneratedMapper.Map(source).ToANew<DateTime[]>(); + + result.ShouldNotBeNull().ShouldBe(yesterday, today, tomorrow); + } + + [Fact] + public void ShouldBuildAComplexTypeListToIListMapper() + { + var source = new List<ProductDto> + { + new ProductDto { ProductId = "Surprise" }, + null, + new ProductDto { ProductId = "Boomstick" } + }; + + var result = GeneratedMapper.Map(source).ToANew<List<ProductDto>>(); + + result.ShouldNotBeNull(); + result.ShouldNotBeSameAs(source); + result.First().ShouldNotBeNull().ProductId.ShouldBe("Surprise"); + result.Second().ShouldBeNull(); + result.Third().ShouldNotBeNull().ProductId.ShouldBe("Boomstick"); + } + } +} diff --git a/AgileMapper.Buildable.UnitTests/WhenBuildingEnumerableMergeMappers.cs b/AgileMapper.Buildable.UnitTests/WhenBuildingEnumerableMergeMappers.cs new file mode 100644 index 000000000..543e1087d --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/WhenBuildingEnumerableMergeMappers.cs @@ -0,0 +1,53 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests +{ + using System.Collections.Generic; + using System.Collections.ObjectModel; + using AgileMapper.UnitTests.Common; + using AgileMapper.UnitTests.Common.TestClasses; + using Xunit; + using GeneratedMapper = Mappers.Mapper; + + public class WhenBuildingEnumerableMergeMappers + { + [Fact] + public void ShouldBuildASimpleTypeIEnumerableToICollectionMapper() + { + IEnumerable<int> source = new[] { 4, 5, 6 }; + ICollection<int> target = new[] { 1, 2, 3 }; + + var result = GeneratedMapper.Map(source).OnTo(target); + + result.ShouldNotBeNull().ShouldNotBeSameAs(target); + result.ShouldBe(1, 2, 3, 4, 5, 6); + } + + [Fact] + public void ShouldBuildASimpleTypeArrayToHashSetMapper() + { + var source = new[] { 1.0m, 2.0m, 3.0m }; + var target = new HashSet<double> { 2.0, 3.0, 4.0 }; + + var result = GeneratedMapper.Map(source).OnTo(target); + + result.ShouldNotBeNull().ShouldBe(2.0, 3.0, 4.0, 1.0); + } + + [Fact] + public void ShouldBuildAComplexTypeArrayToIEnumerableMapper() + { + var source = new[] + { + new Product { ProductId = "Steve" } + }; + + IEnumerable<Product> target = new ReadOnlyCollection<Product>(new[] + { + new Product { ProductId = "Kate" } + }); + + var result = GeneratedMapper.Map(source).OnTo(target); + + result.ShouldNotBeNull().ShouldBe(p => p.ProductId, "Kate", "Steve"); + } + } +} diff --git a/AgileMapper.Buildable.UnitTests/WhenBuildingEnumerableOverwriteMappers.cs b/AgileMapper.Buildable.UnitTests/WhenBuildingEnumerableOverwriteMappers.cs new file mode 100644 index 000000000..801af3070 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/WhenBuildingEnumerableOverwriteMappers.cs @@ -0,0 +1,61 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests +{ + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Linq; + using AgileMapper.UnitTests.Common; + using AgileMapper.UnitTests.Common.TestClasses; + using Xunit; + using GeneratedMapper = Mappers.Mapper; + + public class WhenBuildingEnumerableOverwriteMappers + { + [Fact] + public void ShouldBuildASimpleTypeArrayToArrayMapper() + { + var source = new[] { '5', '5', '5' }; + var target = new[] { 3, 3, 3, 3 }; + + var result = GeneratedMapper.Map(source).Over(target); + + result.ShouldNotBeNull().ShouldNotBeSameAs(target); + result.ShouldBe(5, 5, 5); + } + + [Fact] + public void ShouldBuildASimpleTypeCollectionToListMapper() + { + var source = new Collection<string> { "I", "Will" }; + var target = new List<string> { "You", "Might" }; + + var result = GeneratedMapper.Map(source).Over(target); + + result.ShouldNotBeNull().ShouldBeSameAs(target); + result.SequenceEqual(source).ShouldBeTrue(); + } + + [Fact] + public void ShouldBuildAComplexTypeArrayToReadOnlyCollectionMapper() + { + var source = new[] + { + new ProductDto { ProductId = "1", Price = 1.99m }, + new ProductDto { ProductId = "2", Price = 2.99m }, + }; + + var target = new ReadOnlyCollection<Product>(new List<Product> + { + new Product { ProductId = "2", Price = 4.99 } + }); + + var result = GeneratedMapper.Map(source).Over(target); + + result.ShouldNotBeNull(); + result.Count.ShouldBe(2); + result.First().ProductId.ShouldBe("2"); + result.First().Price.ShouldBe(2.99); + result.Second().ProductId.ShouldBe("1"); + result.Second().Price.ShouldBe(1.99); + } + } +} diff --git a/AgileMapper.Buildable.UnitTests/WhenBuildingRootEnumMappers.cs b/AgileMapper.Buildable.UnitTests/WhenBuildingRootEnumMappers.cs new file mode 100644 index 000000000..410e0cf87 --- /dev/null +++ b/AgileMapper.Buildable.UnitTests/WhenBuildingRootEnumMappers.cs @@ -0,0 +1,31 @@ +namespace AgileObjects.AgileMapper.Buildable.UnitTests +{ + using AgileMapper.UnitTests.Common; + using AgileMapper.UnitTests.Common.TestClasses; + using Mappers.Extensions; + using Xunit; + using GeneratedMapper = Mappers.Mapper; + + public class WhenBuildingRootEnumMappers + { + [Fact] + public void ShouldBuildARootEnumMapper() + { + var enumIdSource = ((int)Title.Mrs).ToString(); + var enumIdResult = GeneratedMapper.Map(enumIdSource).ToANew<Title>(); + enumIdResult.ShouldBe(Title.Mrs); + + const string ENUM_LABEL_SOURCE = nameof(Title.Master); + var enumLabelResult = GeneratedMapper.Map(ENUM_LABEL_SOURCE).ToANew<Title>(); + enumLabelResult.ShouldBe(Title.Master); + } + + [Fact] + public void ShouldBuildARootEnumMappingExtensionMethod() + { + const string ENUM_LABEL_SOURCE = nameof(Title.Count); + var enumLabelResult = ENUM_LABEL_SOURCE.Map().ToANew<Title>(); + enumLabelResult.ShouldBe(Title.Count); + } + } +} diff --git a/AgileMapper.Buildable/AgileMapper.Buildable.csproj b/AgileMapper.Buildable/AgileMapper.Buildable.csproj new file mode 100644 index 000000000..1a1f799fd --- /dev/null +++ b/AgileMapper.Buildable/AgileMapper.Buildable.csproj @@ -0,0 +1,47 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <TargetFrameworks>net461;netstandard2.0</TargetFrameworks> + <AssemblyTitle>AgileObjects.AgileMapper.Buildable</AssemblyTitle> + <AssemblyName>AgileObjects.AgileMapper.Buildable</AssemblyName> + <RootNamespace>AgileObjects.AgileMapper.Buildable</RootNamespace> + <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute> + <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute> + <GenerateDocumentationFile>true</GenerateDocumentationFile> + <TreatWarningsAsErrors>true</TreatWarningsAsErrors> + <BuildExpressions>false</BuildExpressions> + + <PackageId>AgileObjects.AgileMapper.Buildable</PackageId> + <Title>AgileMapper.Buildable + + Mapper, Mapping, "Code Generation" + https://github.com/AgileObjects/AgileMapper + MIT + ../NuGet + + + true + + 0.1.0-preview1 + 0.1.0.0 + 0.1.0.0 + + + + false + + + + + + build + + + + + + + + + diff --git a/AgileMapper.Buildable/BuildableMapperConstants.cs b/AgileMapper.Buildable/BuildableMapperConstants.cs new file mode 100644 index 000000000..f496b4a53 --- /dev/null +++ b/AgileMapper.Buildable/BuildableMapperConstants.cs @@ -0,0 +1,35 @@ +namespace AgileObjects.AgileMapper.Buildable +{ + using System; + using System.Linq.Expressions; + using System.Reflection; + using NetStandardPolyfills; + using ReadableExpressions; + using ReadableExpressions.Extensions; + + internal static class BuildableMapperConstants + { + public static readonly MethodInfo IsAssignableToMethod = typeof(TypeExtensionsPolyfill) + .GetPublicStaticMethod(nameof(TypeExtensionsPolyfill.IsAssignableTo)); + + public static readonly ConstructorInfo NotSupportedCtor = typeof(NotSupportedException) + .GetPublicInstanceConstructor(typeof(string)); + + public static readonly MethodInfo StringConcatMethod = typeof(string).GetPublicStaticMethod( + nameof(string.Concat), + typeof(string), + typeof(string), + typeof(string)); + + public static readonly Expression NullConfiguration = + Expression.Default(typeof(Func)); + + public static readonly MethodInfo GetFriendlyNameMethod = typeof(PublicTypeExtensions) + .GetPublicStaticMethod( + nameof(PublicTypeExtensions.GetFriendlyName), + typeof(Type), + NullConfiguration.Type); + + public const string MapRepeated = nameof(MapRepeated); + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable/BuildableMapperExtensions.cs b/AgileMapper.Buildable/BuildableMapperExtensions.cs new file mode 100644 index 000000000..2f76efe0c --- /dev/null +++ b/AgileMapper.Buildable/BuildableMapperExtensions.cs @@ -0,0 +1,420 @@ +namespace AgileObjects.AgileMapper.Buildable +{ + using System; + using System.CodeDom.Compiler; + using System.Collections.Generic; + using System.Linq; + using System.Linq.Expressions; + using BuildableExpressions; + using BuildableExpressions.SourceCode; + using BuildableExpressions.SourceCode.Api; + using Extensions; + using NetStandardPolyfills; + using ReadableExpressions.Extensions; + using static System.Linq.Expressions.Expression; + using static BuildableExpressions.SourceCode.MemberVisibility; + using static BuildableMapperConstants; + + internal static class BuildableMapperExtensions + { + private const string _toolName = "AgileObjects.AgileMapper.Buildable"; + + private static readonly string _version = typeof(BuildableMapperExtensions) + .Assembly + .GetName() + .Version + .ToString(fieldCount: 4); + + public static IEnumerable GetPlanSourceCodeInCache( + this IMapper mapper, + string rootNamespace) + { + var mappersNamespace = rootNamespace + ".Mappers"; + var mapperClassGroups = mapper.GetMapperClassGroups(); + + if (mapperClassGroups.Count == 0) + { + yield break; + } + + foreach (var mapperGroup in mapperClassGroups) + { + yield return mapperGroup.BuildInstanceMapperClass(mappersNamespace); + } + + yield return mapperClassGroups.BuildStaticMapperClass(mappersNamespace); + yield return mapperClassGroups.BuildMappingExtensionsClass(mappersNamespace); + } + + private static List GetMapperClassGroups(this IMapper mapper) + { + return mapper + .GetPlansInCache() + .GroupBy(plan => plan.Root.SourceType) + .Project(grp => new BuildableMapperGroup(grp.Key, grp.AsEnumerable())) + .OrderBy(grp => grp.MapperName) + .ToList(); + } + + private static SourceCodeExpression BuildInstanceMapperClass( + this BuildableMapperGroup mapperGroup, + string mappersNamespace) + { + return BuildableExpression.SourceCode(sourceCode => + { + sourceCode.AddGeneratedCodeHeader(); + sourceCode.SetNamespace(mappersNamespace); + + mapperGroup.MapperClass = sourceCode.AddClass(mapperGroup.MapperName, mapperClass => + { + mapperGroup.MapperInstance = mapperClass.ThisInstanceExpression; + + mapperClass.AddGeneratedCodeAttribute(); + mapperClass.SetBaseType(mapperGroup.MapperBaseType); + + mapperClass.AddConstructor(ctor => + { + ctor.SetConstructorCall( + mapperGroup.MapperBaseTypeConstructor, + ctor.AddParameter(mapperGroup.SourceType, "source")); + + ctor.SetBody(Empty()); + }); + + foreach (var planAndMappingMethods in mapperGroup.MappingMethodsByPlan) + { + var plan = planAndMappingMethods.Key; + var mappingMethods = planAndMappingMethods.Value; + + foreach (var repeatPlan in plan.Skip(1)) + { + mappingMethods.Add(mapperClass.AddMethod(MapRepeated, doMapping => + { + doMapping.SetVisibility(Private); + doMapping.SetStatic(); + doMapping.SetBody(repeatPlan.Mapping); + })); + } + + mappingMethods.Insert(0, mapperClass.AddMethod(plan.RuleSetName, doMapping => + { + doMapping.SetVisibility(Private); + doMapping.SetStatic(); + doMapping.SetBody(plan.Root.Mapping); + })); + } + + RepeatMappingCallReplacer.Replace(mapperGroup); + + var allRuleSetMapMethodInfos = mapperGroup + .MappingMethodsByPlan.Values + .SelectMany(methods => methods) + .Filter(method => method.Name != MapRepeated) + .Project(method => new MapMethodInfo(mapperGroup, method)) + .GroupBy(m => m.RuleSetName) + .Select(methodGroup => methodGroup.ToList()); + + foreach (var ruleSetMapMethodInfos in allRuleSetMapMethodInfos) + { + AddMappingMethodsFor(mapperClass, ruleSetMapMethodInfos); + } + }); + }); + } + + private static void AddMappingMethodsFor( + IClassMemberConfigurator mapperClass, + IList mapMethodInfos) + { + var ruleSetName = mapMethodInfos[0].RuleSetName; + + switch (ruleSetName) + { + case "CreateNew": + AddCreateNewMethod(mapperClass, mapMethodInfos); + return; + + case "Merge": + AddUpdateInstanceMapMethod(mapperClass, mapMethodInfos, "OnTo"); + return; + + case "Overwrite": + AddUpdateInstanceMapMethod(mapperClass, mapMethodInfos, "Over"); + return; + + default: + throw new NotSupportedException($"Unable to map rule set '{ruleSetName}'"); + } + } + + private static void AddCreateNewMethod( + IClassMemberConfigurator mapperClass, + IList mapMethodInfos) + { + mapperClass.AddMethod("ToANew", mapNewMethod => + { + var useTypeConstraint = UseTypeConstraint(mapMethodInfos); + + var targetGenericParameter = mapNewMethod.AddGenericParameter("TTarget", param => + { + if (useTypeConstraint) + { + param.AddTypeConstraints(mapMethodInfos[0].TargetType); + } + }); + + if (useTypeConstraint) + { + mapNewMethod.SetBody(mapMethodInfos[0].CreateMapCall(Default)); + return; + } + + var targetGenericParameterType = targetGenericParameter.Type; + var typeofTarget = BuildableExpression.TypeOf(targetGenericParameter); + + var mappingExpressions = new List(); + var returnTarget = Label(targetGenericParameterType, "Return"); + + foreach (var mapMethodInfo in mapMethodInfos) + { + var targetType = mapMethodInfo.TargetType; + var typeofTargetType = BuildableExpression.TypeOf(targetType); + + var typesAssignable = targetType.IsSealed() + ? (Expression)Equal(typeofTarget, typeofTargetType) + : Call(IsAssignableToMethod, typeofTarget, typeofTargetType); + + var mapCall = mapMethodInfo.CreateMapCall(Default); + var mapCallResultAsObject = Convert(mapCall, typeof(object)); + var mapCallResultAsTarget = Convert(mapCallResultAsObject, targetGenericParameterType); + var returnMapResult = Return(returnTarget, mapCallResultAsTarget); + + var ifTypesMatchMap = IfThen(typesAssignable, returnMapResult); + mappingExpressions.Add(ifTypesMatchMap); + } + + mappingExpressions.Add(GetThrowTargetNotSupportedException(mapMethodInfos[0], targetGenericParameter)); + mappingExpressions.Add(Label(returnTarget, Default(targetGenericParameterType))); + + mapNewMethod.SetBody(Block(mappingExpressions)); + }); + } + + private static bool UseTypeConstraint(IList mapMethodInfos) + { + if (mapMethodInfos.Count != 1) + { + return false; + } + + var firstMapMethod = mapMethodInfos[0]; + + if (firstMapMethod.HasDerivedTypes) + { + return false; + } + + var targetType = firstMapMethod.TargetType; + + return !(targetType.IsArray || targetType.IsEnum()); + } + + private static Expression GetThrowTargetNotSupportedException( + MapMethodInfo mapMethodInfo, + TypeExpression targetGenericParameter) + { + var getErrorMessageCall = Call( + StringConcatMethod, + Constant( + $"Unable to perform a '{mapMethodInfo.RuleSetName}' mapping " + + $"from source type '{mapMethodInfo.SourceType.GetFriendlyName()}' " + + "to target type '", + typeof(string)), + Call( + GetFriendlyNameMethod, + BuildableExpression.TypeOf(targetGenericParameter), + NullConfiguration), + Constant("'", typeof(string))); + + return Throw(New(NotSupportedCtor, getErrorMessageCall)); + } + + private static void AddUpdateInstanceMapMethod( + IClassMemberConfigurator mapperClass, + IEnumerable mapMethodInfos, + string apiMethodName) + { + foreach (var mapMethodInfo in mapMethodInfos) + { + mapperClass.AddMethod(apiMethodName, mapMethod => + { + mapMethod.SetBody(mapMethodInfo + .CreateMapCall(t => mapMethod.AddParameter(t, "target"))); + }); + } + } + + private static SourceCodeExpression BuildStaticMapperClass( + this IEnumerable mapperClassGroups, + string mappersNamespace) + { + return BuildableExpression.SourceCode(sourceCode => + { + sourceCode.AddGeneratedCodeHeader(); + sourceCode.SetNamespace(mappersNamespace); + + sourceCode.AddClass("Mapper", staticMapperClass => + { + staticMapperClass.AddGeneratedCodeAttribute(); + staticMapperClass.SetStatic(); + staticMapperClass.AddStaticMappingMethods(mapperClassGroups); + }); + }); + } + + private static SourceCodeExpression BuildMappingExtensionsClass( + this IEnumerable mapperClassGroups, + string mappersNamespace) + { + return BuildableExpression.SourceCode(sourceCode => + { + sourceCode.AddGeneratedCodeHeader(); + sourceCode.SetNamespace(mappersNamespace + ".Extensions"); + + sourceCode.AddClass("MappingExtensions", mappingExtensionsClass => + { + mappingExtensionsClass.AddGeneratedCodeAttribute(); + mappingExtensionsClass.SetStatic(); + + mappingExtensionsClass.AddStaticMappingMethods( + mapperClassGroups, + method => method.SetExtensionMethod()); + }); + }); + } + + private static void AddStaticMappingMethods( + this IClassMemberConfigurator mappingClass, + IEnumerable mapperClassGroups, + Action methodConfig = null) + { + foreach (var mapperClassGroup in mapperClassGroups) + { + mappingClass.AddMethod("Map", mapMethod => + { + methodConfig?.Invoke(mapMethod); + mapperClassGroup.Configure(mapMethod); + }); + + if (mapperClassGroup.IncludeDeepClone) + { + mappingClass.AddMethod("DeepClone", mapMethod => + { + methodConfig?.Invoke(mapMethod); + mapperClassGroup.ConfigureDeepClone(mapMethod); + }); + } + } + } + + private static void Configure( + this BuildableMapperGroup mapperClassGroup, + IConcreteTypeMethodExpressionConfigurator mapMethod) + { + mapMethod.SetBody(GetMapperInstantiation(mapperClassGroup, mapMethod)); + } + + private static void ConfigureDeepClone( + this BuildableMapperGroup mapperClassGroup, + IConcreteTypeMethodExpressionConfigurator mapMethod) + { + var newMapper = GetMapperInstantiation(mapperClassGroup, mapMethod); + + var createNewCall = Call( + newMapper, + newMapper.Type + .GetMethod("ToANew")! + .MakeGenericMethod(mapperClassGroup.SourceType)); + + mapMethod.SetBody(createNewCall); + } + + private static NewExpression GetMapperInstantiation( + BuildableMapperGroup mapperClassGroup, + IMethodExpressionBaseConfigurator mapMethod) + { + var sourceType = mapperClassGroup.SourceType; + var mapperClass = mapperClassGroup.MapperClass; + + var sourceParameter = mapMethod + .AddParameter(sourceType, "source"); + + var newMapper = New( + mapperClass.Type.GetPublicInstanceConstructor(sourceType), + sourceParameter); + + return newMapper; + } + + private static void AddGeneratedCodeHeader( + this ISourceCodeExpressionConfigurator sourceCode) + { + sourceCode.SetHeader(@$" +//------------------------------------------------------------------------------ +// +// This code was generated by {_toolName}. +// Runtime Version: {_version} +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------".TrimStart()); + } + + private static void AddGeneratedCodeAttribute( + this IAttributableExpressionConfigurator mapperClass) + { + mapperClass.AddAttribute(typeof(GeneratedCodeAttribute), cfg => + { + cfg.SetConstructorArguments(_toolName, _version); + }); + } + + #region Helper Members + + private class MapMethodInfo + { + private readonly BuildableMapperGroup _mapperGroup; + private readonly MethodExpression _mapMethod; + + public MapMethodInfo( + BuildableMapperGroup mapperGroup, + MethodExpression mapMethod) + { + _mapperGroup = mapperGroup; + _mapMethod = mapMethod; + TargetType = mapMethod.GetTargetType(); + } + + public string RuleSetName => _mapMethod.Name; + + public Type SourceType => _mapperGroup.SourceType; + + public Type TargetType { get; } + + public bool HasDerivedTypes => _mapperGroup.HasDerivedTypes; + + public Expression CreateMapCall(Func targetFactory) + { + var createMappingDataCall = Call( + _mapperGroup.MapperInstance, + _mapperGroup.CreateRootMappingDataMethod.MakeGenericMethod(TargetType), + targetFactory.Invoke(TargetType)); + + return Call(_mapMethod.MethodInfo, createMappingDataCall); + } + } + + #endregion + } +} diff --git a/AgileMapper.Buildable/BuildableMapperGroup.cs b/AgileMapper.Buildable/BuildableMapperGroup.cs new file mode 100644 index 000000000..099aa39db --- /dev/null +++ b/AgileMapper.Buildable/BuildableMapperGroup.cs @@ -0,0 +1,70 @@ +namespace AgileObjects.AgileMapper.Buildable +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Linq.Expressions; + using System.Reflection; + using BuildableExpressions.SourceCode; + using NetStandardPolyfills; + using Plans; + using ReadableExpressions.Extensions; + + internal class BuildableMapperGroup + { + private bool? _hasDerivedTypes; + private bool? _includeDeepClone; + private MethodInfo _createChildMappingDataMethod; + + public BuildableMapperGroup( + Type sourceType, + IEnumerable plans) + { + SourceType = sourceType; + MapperBaseType = typeof(MappingExecutionContextBase<>).MakeGenericType(sourceType); + MapperBaseTypeConstructor = MapperBaseType.GetNonPublicInstanceConstructor(sourceType); + CreateRootMappingDataMethod = MapperBaseType.GetNonPublicInstanceMethod("CreateRootMappingData"); + MapperName = sourceType.GetVariableNameInPascalCase() + "Mapper"; + MappingMethodsByPlan = plans.ToDictionary(p => p, _ => new List()); + } + + public Type SourceType { get; } + + public bool HasDerivedTypes + => _hasDerivedTypes ??= DetermineIfHasDerivedTypes(); + + private bool DetermineIfHasDerivedTypes() + { + return MappingMethodsByPlan.Keys + .Any(plan => plan.Any(p => p.HasDerivedTypes)); + } + + public bool IncludeDeepClone + => _includeDeepClone ??= DetermineIfIncludeDeepClone(); + + private bool DetermineIfIncludeDeepClone() + { + return MappingMethodsByPlan.Keys.Any(plan => + plan.RuleSetName == "CreateNew" && + plan.Root.TargetType == SourceType); + } + + public Type MapperBaseType { get; } + + public ConstructorInfo MapperBaseTypeConstructor { get; } + + public MethodInfo CreateRootMappingDataMethod { get; } + + public MethodInfo CreateChildMappingDataMethod + => _createChildMappingDataMethod ??= MapperBaseType + .GetNonPublicStaticMethod("CreateChildMappingData"); + + public string MapperName { get; } + + public Expression MapperInstance { get; set; } + + public ClassExpression MapperClass { get; set; } + + public IDictionary> MappingMethodsByPlan { get; } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable/BuildableMapperHelperExtensions.cs b/AgileMapper.Buildable/BuildableMapperHelperExtensions.cs new file mode 100644 index 000000000..47724cdf1 --- /dev/null +++ b/AgileMapper.Buildable/BuildableMapperHelperExtensions.cs @@ -0,0 +1,12 @@ +namespace AgileObjects.AgileMapper.Buildable +{ + using System; + using BuildableExpressions.SourceCode; + using NetStandardPolyfills; + + internal static class BuildableMapperHelperExtensions + { + public static Type GetTargetType(this MethodExpression mapMethod) + => mapMethod.Parameters[0].Type.GetGenericTypeArguments()[1]; + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable/Configuration/BuildableMapperConfiguration.cs b/AgileMapper.Buildable/Configuration/BuildableMapperConfiguration.cs new file mode 100644 index 000000000..bb2dcbe91 --- /dev/null +++ b/AgileMapper.Buildable/Configuration/BuildableMapperConfiguration.cs @@ -0,0 +1,12 @@ +namespace AgileObjects.AgileMapper.Buildable.Configuration +{ + using AgileMapper.Configuration; + + /// + /// Base class for multiple, buildable mapper configuration. Derived classes will be executed + /// to set up mapping configurations for which Mapper source code should be generated. + /// + public abstract class BuildableMapperConfiguration : MapperConfiguration + { + } +} diff --git a/AgileMapper.Buildable/MSBuild/AgileObjects.AgileMapper.Buildable.targets b/AgileMapper.Buildable/MSBuild/AgileObjects.AgileMapper.Buildable.targets new file mode 100644 index 000000000..9aeb9a767 --- /dev/null +++ b/AgileMapper.Buildable/MSBuild/AgileObjects.AgileMapper.Buildable.targets @@ -0,0 +1,14 @@ + + + + $(MappersGenerator) + $(MappersOutputProject) + AgileMapper.Buildable: + + + true + + + + \ No newline at end of file diff --git a/AgileMapper.Buildable/MapperBuilder.cs b/AgileMapper.Buildable/MapperBuilder.cs new file mode 100644 index 000000000..e90835fa4 --- /dev/null +++ b/AgileMapper.Buildable/MapperBuilder.cs @@ -0,0 +1,40 @@ +namespace AgileObjects.AgileMapper.Buildable +{ + using System; + using System.Collections.Generic; + using System.Linq; + using BuildableExpressions; + using BuildableExpressions.SourceCode; + using Configuration; + + /// + /// An which generates source code for configured + /// mappers. + /// + public class MapperBuilder : ISourceCodeExpressionBuilder + { + /// + public IEnumerable Build(IExpressionBuildContext context) + { + using var mapper = Mapper.CreateNew(); + + mapper.WhenMapping + .UseConfigurations.From(context.ProjectAssemblies); + + var mapperSourceCode = mapper + .GetPlanSourceCodeInCache(context.RootNamespace) + .ToList(); + + if (mapperSourceCode.Any()) + { + return mapperSourceCode; + } + + context.Log( + $"no {nameof(BuildableMapperConfiguration)}-derived " + + "Mapper configurations found"); + + return Array.Empty(); + } + } +} \ No newline at end of file diff --git a/AgileMapper.Buildable/RepeatMappingCallReplacer.cs b/AgileMapper.Buildable/RepeatMappingCallReplacer.cs new file mode 100644 index 000000000..fe0906ccb --- /dev/null +++ b/AgileMapper.Buildable/RepeatMappingCallReplacer.cs @@ -0,0 +1,170 @@ +namespace AgileObjects.AgileMapper.Buildable +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Linq.Expressions; + using BuildableExpressions.SourceCode; + using Extensions; + using NetStandardPolyfills; + using static System.Linq.Expressions.Expression; + using static BuildableMapperConstants; + + internal class RepeatMappingCallReplacer : ExpressionVisitor + { + private readonly IDictionary _repeatMappingCallReplacements; + + private RepeatMappingCallReplacer( + IDictionary repeatMappingCallReplacements) + { + _repeatMappingCallReplacements = repeatMappingCallReplacements; + } + + public static void Replace(BuildableMapperGroup mapperGroup) + { + var mapMethodGroups = mapperGroup + .MappingMethodsByPlan.Values + .Filter(mapMethods => mapMethods.Count > 1) + .ToList(); + + if (mapMethodGroups.Count == 0) + { + return; + } + + foreach (var mapMethodGroup in mapMethodGroups) + { + var repeatMappingCallReplacements = MappingCallFinder + .GetRepeatMappingCallReplacements(mapperGroup, mapMethodGroup); + + var replacer = new RepeatMappingCallReplacer(repeatMappingCallReplacements); + + foreach (var mapMethod in mapMethodGroup) + { + replacer.ReplaceIn(mapMethod); + } + } + } + + private void ReplaceIn(MethodExpressionBase mapMethod) + { + mapMethod.Update(VisitAndConvert( + mapMethod.Body, + nameof(RepeatMappingCallReplacer))); + } + + protected override Expression VisitMethodCall(MethodCallExpression methodCall) + { + return _repeatMappingCallReplacements.TryGetValue(methodCall, out var replacement) + ? replacement + : methodCall; + } + + #region Helper Classes + + private class MappingCallFinder : ExpressionVisitor + { + private readonly BuildableMapperGroup _mapperGroup; + private readonly IDictionary _mapMethodsByMappingTypes; + private readonly IDictionary _mapRepeatedCallsByMappingTypes; + + private MappingCallFinder( + BuildableMapperGroup mapperGroup, + IEnumerable mapMethods) + { + _mapperGroup = mapperGroup; + + _mapRepeatedCallsByMappingTypes = new Dictionary(); + + _mapMethodsByMappingTypes = mapMethods + .Skip(1) + .ToDictionary(m => new MappingTypePair(m), MappingTypePair.Comparer); + } + + public static IDictionary GetRepeatMappingCallReplacements( + BuildableMapperGroup mapperGroup, + ICollection mapMethods) + { + var finder = new MappingCallFinder(mapperGroup, mapMethods); + + foreach (var mapMethod in mapMethods) + { + finder.Visit(mapMethod.Body); + } + + return finder._mapRepeatedCallsByMappingTypes; + } + + protected override Expression VisitMethodCall(MethodCallExpression methodCall) + { + if (methodCall.Method.Name != MapRepeated) + { + return methodCall; + } + + var sourceObject = methodCall.Arguments[0]; + var targetObject = methodCall.Arguments[1]; + var typePair = new MappingTypePair(sourceObject.Type, targetObject.Type); + + var mapRepeatedMethod = _mapMethodsByMappingTypes[typePair]; + + var createChildMappingDataMethod = _mapperGroup + .CreateChildMappingDataMethod + .MakeGenericMethod(typePair.SourceType, typePair.TargetType); + + var createMappingDataCall = Call( + createChildMappingDataMethod, + sourceObject, + targetObject, + methodCall.Object!); + + _mapRepeatedCallsByMappingTypes.Add( + methodCall, + Call(mapRepeatedMethod.MethodInfo, createMappingDataCall)); + + return methodCall; + } + } + + private class MappingTypePair + { + public static readonly IEqualityComparer Comparer = + new MappingTypePairComparer(); + + public MappingTypePair(MethodExpressionBase mapMethod) + { + var mappingTypes = mapMethod + .Parameters[0].Type + .GetGenericTypeArguments(); + + SourceType = mappingTypes[0]; + TargetType = mappingTypes[1]; + } + + public MappingTypePair(Type sourceType, Type targetType) + { + SourceType = sourceType; + TargetType = targetType; + } + + public Type SourceType { get; } + + public Type TargetType { get; } + + private class MappingTypePairComparer : IEqualityComparer + { + public bool Equals(MappingTypePair x, MappingTypePair y) + { + // ReSharper disable PossibleNullReferenceException + return x.SourceType == y.SourceType && + x.TargetType == y.TargetType; + // ReSharper restore PossibleNullReferenceException + } + + public int GetHashCode(MappingTypePair obj) => 0; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/AgileMapper.PerformanceTester.Net461/AgileMapper.PerformanceTester.Net461.csproj b/AgileMapper.PerformanceTester.Net461/AgileMapper.PerformanceTester.Net461.csproj index 7eba9c9cb..2d5e2677c 100644 --- a/AgileMapper.PerformanceTester.Net461/AgileMapper.PerformanceTester.Net461.csproj +++ b/AgileMapper.PerformanceTester.Net461/AgileMapper.PerformanceTester.Net461.csproj @@ -34,11 +34,11 @@ 4 - - ..\packages\AgileObjects.NetStandardPolyfills.1.5.0\lib\net40\AgileObjects.NetStandardPolyfills.dll + + ..\packages\AgileObjects.NetStandardPolyfills.1.6.0\lib\net40\AgileObjects.NetStandardPolyfills.dll - - ..\packages\AgileObjects.ReadableExpressions.2.6.0\lib\net40\AgileObjects.ReadableExpressions.dll + + ..\packages\AgileObjects.ReadableExpressions.3.0.0-preview1\lib\net40\AgileObjects.ReadableExpressions.dll ..\packages\AutoMapper.7.0.1\lib\net45\AutoMapper.dll diff --git a/AgileMapper.PerformanceTester.Net461/App.config b/AgileMapper.PerformanceTester.Net461/App.config index 3f18c82e4..e06a6e682 100644 --- a/AgileMapper.PerformanceTester.Net461/App.config +++ b/AgileMapper.PerformanceTester.Net461/App.config @@ -1,13 +1,13 @@ - + - + - - + + diff --git a/AgileMapper.PerformanceTester.Net461/packages.config b/AgileMapper.PerformanceTester.Net461/packages.config index b320b55a4..fef25c884 100644 --- a/AgileMapper.PerformanceTester.Net461/packages.config +++ b/AgileMapper.PerformanceTester.Net461/packages.config @@ -1,7 +1,7 @@  - - + + diff --git a/AgileMapper.PerformanceTesting/AgileMapper.PerformanceTesting.csproj b/AgileMapper.PerformanceTesting/AgileMapper.PerformanceTesting.csproj index 8c7a7569b..a16bd6d14 100644 --- a/AgileMapper.PerformanceTesting/AgileMapper.PerformanceTesting.csproj +++ b/AgileMapper.PerformanceTesting/AgileMapper.PerformanceTesting.csproj @@ -9,7 +9,7 @@ - + diff --git a/AgileMapper.UnitTests.Common/ShouldExtensions.cs b/AgileMapper.UnitTests.Common/FluentAssertionExtensions.cs similarity index 96% rename from AgileMapper.UnitTests.Common/ShouldExtensions.cs rename to AgileMapper.UnitTests.Common/FluentAssertionExtensions.cs index 9eb41e0c4..65089107c 100644 --- a/AgileMapper.UnitTests.Common/ShouldExtensions.cs +++ b/AgileMapper.UnitTests.Common/FluentAssertionExtensions.cs @@ -9,7 +9,7 @@ using NetStandardPolyfills; using ReadableExpressions.Extensions; - public static class ShouldExtensions + public static class FluentAssertionExtensions { public static void ShouldBeDefault(this T value) => value.ShouldBe(default(T)); @@ -58,7 +58,7 @@ public static void ShouldBe(this TActual value, TExpected ex } } - private static readonly MethodInfo _areEqualMethod = typeof(ShouldExtensions) + private static readonly MethodInfo _areEqualMethod = typeof(FluentAssertionExtensions) .GetNonPublicStaticMethod("AreEqual"); private static bool AreEqual(TExpected expected, TActual actual) @@ -170,30 +170,34 @@ public static void ShouldBe(this IEnumerable actualValues, IEnumerab actualValues.Project(converter).SequenceEqual(expectedValues).ShouldBeTrue(); } - public static void ShouldNotBe(this TActual value, TExpected expectedValue) + public static void ShouldNotBe(this TActual value, TExpected unexpectedValue) { - if (AreEqual(expectedValue, value)) + if (AreEqual(unexpectedValue, value)) { - Asplode("Not " + expectedValue, value.ToString()); + Asplode("Not " + unexpectedValue, value.ToString()); } } - public static void ShouldNotBeSameAs(this T actualItem, T nonExpectedItem) + public static T ShouldNotBeSameAs(this T actualItem, T nonExpectedItem) where T : class { if (ReferenceEquals(nonExpectedItem, actualItem)) { Asplode("Not " + nonExpectedItem, nonExpectedItem.ToString()); } + + return actualItem; } - public static void ShouldBeSameAs(this T actualItem, T expectedItem) + public static T ShouldBeSameAs(this T actualItem, T expectedItem) where T : class { if (!ReferenceEquals(expectedItem, actualItem)) { Asplode(expectedItem.ToString(), actualItem.ToString()); } + + return expectedItem; } public static void ShouldBeTrue(this bool? value) diff --git a/AgileMapper.UnitTests/TestClasses/Address.cs b/AgileMapper.UnitTests.Common/TestClasses/Address.cs similarity index 75% rename from AgileMapper.UnitTests/TestClasses/Address.cs rename to AgileMapper.UnitTests.Common/TestClasses/Address.cs index ab82220f6..b48cc3c74 100644 --- a/AgileMapper.UnitTests/TestClasses/Address.cs +++ b/AgileMapper.UnitTests.Common/TestClasses/Address.cs @@ -1,4 +1,4 @@ -namespace AgileObjects.AgileMapper.UnitTests.TestClasses +namespace AgileObjects.AgileMapper.UnitTests.Common.TestClasses { public sealed class Address { diff --git a/AgileMapper.UnitTests/TestClasses/Child.cs b/AgileMapper.UnitTests.Common/TestClasses/Child.cs similarity index 54% rename from AgileMapper.UnitTests/TestClasses/Child.cs rename to AgileMapper.UnitTests.Common/TestClasses/Child.cs index a48a58364..8f2f01fe0 100644 --- a/AgileMapper.UnitTests/TestClasses/Child.cs +++ b/AgileMapper.UnitTests.Common/TestClasses/Child.cs @@ -1,6 +1,6 @@ -namespace AgileObjects.AgileMapper.UnitTests.TestClasses +namespace AgileObjects.AgileMapper.UnitTests.Common.TestClasses { - internal class Child + public class Child { public string Name { get; set; } diff --git a/AgileMapper.UnitTests.Common/TestClasses/MegaProduct.cs b/AgileMapper.UnitTests.Common/TestClasses/MegaProduct.cs new file mode 100644 index 000000000..4e6ac04b4 --- /dev/null +++ b/AgileMapper.UnitTests.Common/TestClasses/MegaProduct.cs @@ -0,0 +1,7 @@ +namespace AgileObjects.AgileMapper.UnitTests.Common.TestClasses +{ + public class MegaProduct : Product + { + public decimal HowMega { get; set; } + } +} \ No newline at end of file diff --git a/AgileMapper.UnitTests/TestClasses/Parent.cs b/AgileMapper.UnitTests.Common/TestClasses/Parent.cs similarity index 53% rename from AgileMapper.UnitTests/TestClasses/Parent.cs rename to AgileMapper.UnitTests.Common/TestClasses/Parent.cs index 1b59838c8..10824e794 100644 --- a/AgileMapper.UnitTests/TestClasses/Parent.cs +++ b/AgileMapper.UnitTests.Common/TestClasses/Parent.cs @@ -1,6 +1,6 @@ -namespace AgileObjects.AgileMapper.UnitTests.TestClasses +namespace AgileObjects.AgileMapper.UnitTests.Common.TestClasses { - internal class Parent + public class Parent { public string Name { get; set; } diff --git a/AgileMapper.UnitTests/TestClasses/Product.cs b/AgileMapper.UnitTests.Common/TestClasses/Product.cs similarity index 67% rename from AgileMapper.UnitTests/TestClasses/Product.cs rename to AgileMapper.UnitTests.Common/TestClasses/Product.cs index fd839862d..3ee92ab11 100644 --- a/AgileMapper.UnitTests/TestClasses/Product.cs +++ b/AgileMapper.UnitTests.Common/TestClasses/Product.cs @@ -1,6 +1,6 @@ -namespace AgileObjects.AgileMapper.UnitTests.TestClasses +namespace AgileObjects.AgileMapper.UnitTests.Common.TestClasses { - internal class Product + public class Product { public string ProductId { diff --git a/AgileMapper.UnitTests/TestClasses/ProductDto.cs b/AgileMapper.UnitTests.Common/TestClasses/ProductDto.cs similarity index 52% rename from AgileMapper.UnitTests/TestClasses/ProductDto.cs rename to AgileMapper.UnitTests.Common/TestClasses/ProductDto.cs index 4759b9384..503759a45 100644 --- a/AgileMapper.UnitTests/TestClasses/ProductDto.cs +++ b/AgileMapper.UnitTests.Common/TestClasses/ProductDto.cs @@ -1,6 +1,6 @@ -namespace AgileObjects.AgileMapper.UnitTests.TestClasses +namespace AgileObjects.AgileMapper.UnitTests.Common.TestClasses { - internal class ProductDto + public class ProductDto { public string ProductId { get; set; } diff --git a/AgileMapper.UnitTests.Common/TestClasses/ProductDtoMega.cs b/AgileMapper.UnitTests.Common/TestClasses/ProductDtoMega.cs new file mode 100644 index 000000000..0ab231a78 --- /dev/null +++ b/AgileMapper.UnitTests.Common/TestClasses/ProductDtoMega.cs @@ -0,0 +1,7 @@ +namespace AgileObjects.AgileMapper.UnitTests.Common.TestClasses +{ + public class ProductDtoMega : ProductDto + { + public string HowMega { get; set; } + } +} \ No newline at end of file diff --git a/AgileMapper.UnitTests/TestClasses/PublicField.cs b/AgileMapper.UnitTests.Common/TestClasses/PublicField.cs similarity index 51% rename from AgileMapper.UnitTests/TestClasses/PublicField.cs rename to AgileMapper.UnitTests.Common/TestClasses/PublicField.cs index 296b0147c..d956a0ddd 100644 --- a/AgileMapper.UnitTests/TestClasses/PublicField.cs +++ b/AgileMapper.UnitTests.Common/TestClasses/PublicField.cs @@ -1,4 +1,4 @@ -namespace AgileObjects.AgileMapper.UnitTests.TestClasses +namespace AgileObjects.AgileMapper.UnitTests.Common.TestClasses { public class PublicField { diff --git a/AgileMapper.UnitTests/TestClasses/PublicProperty.cs b/AgileMapper.UnitTests.Common/TestClasses/PublicProperty.cs similarity index 65% rename from AgileMapper.UnitTests/TestClasses/PublicProperty.cs rename to AgileMapper.UnitTests.Common/TestClasses/PublicProperty.cs index 0932c623f..6614bd9c3 100644 --- a/AgileMapper.UnitTests/TestClasses/PublicProperty.cs +++ b/AgileMapper.UnitTests.Common/TestClasses/PublicProperty.cs @@ -1,4 +1,4 @@ -namespace AgileObjects.AgileMapper.UnitTests.TestClasses +namespace AgileObjects.AgileMapper.UnitTests.Common.TestClasses { public class PublicProperty { diff --git a/AgileMapper.UnitTests/TestClasses/PublicTwoFields.cs b/AgileMapper.UnitTests.Common/TestClasses/PublicTwoFields.cs similarity index 61% rename from AgileMapper.UnitTests/TestClasses/PublicTwoFields.cs rename to AgileMapper.UnitTests.Common/TestClasses/PublicTwoFields.cs index 7db5078dc..42e0b60eb 100644 --- a/AgileMapper.UnitTests/TestClasses/PublicTwoFields.cs +++ b/AgileMapper.UnitTests.Common/TestClasses/PublicTwoFields.cs @@ -1,4 +1,4 @@ -namespace AgileObjects.AgileMapper.UnitTests.TestClasses +namespace AgileObjects.AgileMapper.UnitTests.Common.TestClasses { public class PublicTwoFields { diff --git a/AgileMapper.UnitTests.Common/TestClasses/ToTargetValueSource.cs b/AgileMapper.UnitTests.Common/TestClasses/ToTargetValueSource.cs new file mode 100644 index 000000000..6f5f74f8c --- /dev/null +++ b/AgileMapper.UnitTests.Common/TestClasses/ToTargetValueSource.cs @@ -0,0 +1,9 @@ +namespace AgileObjects.AgileMapper.UnitTests.Common.TestClasses +{ + public class ToTargetValueSource + { + public T1 Value1 { get; set; } + + public PublicTwoFields Value { get; set; } + } +} \ No newline at end of file diff --git a/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj b/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj index 37b52c67a..88010025d 100644 --- a/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj +++ b/AgileMapper.UnitTests.Net35/AgileMapper.UnitTests.Net35.csproj @@ -2,7 +2,6 @@ net35 - 8.0 AgileObjects.AgileMapper.UnitTests.Net35 AgileObjects.AgileMapper.UnitTests.Net35 true diff --git a/AgileMapper.UnitTests.NetCore/AgileMapper.UnitTests.NetCore.csproj b/AgileMapper.UnitTests.NetCore/AgileMapper.UnitTests.NetCore.csproj index 347b99318..22fa55ed0 100644 --- a/AgileMapper.UnitTests.NetCore/AgileMapper.UnitTests.NetCore.csproj +++ b/AgileMapper.UnitTests.NetCore/AgileMapper.UnitTests.NetCore.csproj @@ -2,8 +2,6 @@ netcoreapp1.0 - 1.1.13 - 8.0 AgileObjects.AgileMapper.UnitTests.NetCore AgileObjects.AgileMapper.UnitTests true diff --git a/AgileMapper.UnitTests.NetCore2/AgileMapper.UnitTests.NetCore2.csproj b/AgileMapper.UnitTests.NetCore2/AgileMapper.UnitTests.NetCore2.csproj index 94c8b6fa7..e0aa554d3 100644 --- a/AgileMapper.UnitTests.NetCore2/AgileMapper.UnitTests.NetCore2.csproj +++ b/AgileMapper.UnitTests.NetCore2/AgileMapper.UnitTests.NetCore2.csproj @@ -1,9 +1,7 @@  - netcoreapp2.2 - 2.2.7 - 8.0 + netcoreapp2.1 AgileObjects.AgileMapper.UnitTests.NetCore2 AgileObjects.AgileMapper.UnitTests true diff --git a/AgileMapper.UnitTests.NetCore3/AgileMapper.UnitTests.NetCore3.csproj b/AgileMapper.UnitTests.NetCore3/AgileMapper.UnitTests.NetCore3.csproj index 989c825d2..a2e953764 100644 --- a/AgileMapper.UnitTests.NetCore3/AgileMapper.UnitTests.NetCore3.csproj +++ b/AgileMapper.UnitTests.NetCore3/AgileMapper.UnitTests.NetCore3.csproj @@ -2,8 +2,6 @@ netcoreapp3.1 - 3.1.4 - 8.0 AgileObjects.AgileMapper.UnitTests.NetCore3 AgileObjects.AgileMapper.UnitTests true diff --git a/AgileMapper.UnitTests.NonParallel/AgileMapper.UnitTests.NonParallel.csproj b/AgileMapper.UnitTests.NonParallel/AgileMapper.UnitTests.NonParallel.csproj index 5d44d2ce7..f4d38bc3f 100644 --- a/AgileMapper.UnitTests.NonParallel/AgileMapper.UnitTests.NonParallel.csproj +++ b/AgileMapper.UnitTests.NonParallel/AgileMapper.UnitTests.NonParallel.csproj @@ -2,7 +2,6 @@ net461 - 8.0 true AgileObjects.AgileMapper.UnitTests.NonParallel AgileObjects.AgileMapper.UnitTests.NonParallel diff --git a/AgileMapper.UnitTests.NonParallel/Configuration/WhenConfiguringDataSources.cs b/AgileMapper.UnitTests.NonParallel/Configuration/WhenConfiguringDataSources.cs index 1b2c04f03..e4cb7a9d4 100644 --- a/AgileMapper.UnitTests.NonParallel/Configuration/WhenConfiguringDataSources.cs +++ b/AgileMapper.UnitTests.NonParallel/Configuration/WhenConfiguringDataSources.cs @@ -1,7 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.NonParallel.Configuration { using Common; - using TestClasses; + using Common.TestClasses; using Xunit; public class WhenConfiguringDataSources : NonParallelTestsBase diff --git a/AgileMapper.UnitTests.NonParallel/Configuration/WhenConfiguringMappingCallbacks.cs b/AgileMapper.UnitTests.NonParallel/Configuration/WhenConfiguringMappingCallbacks.cs index c64af2613..6d364a143 100644 --- a/AgileMapper.UnitTests.NonParallel/Configuration/WhenConfiguringMappingCallbacks.cs +++ b/AgileMapper.UnitTests.NonParallel/Configuration/WhenConfiguringMappingCallbacks.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using Common; + using Common.TestClasses; using TestClasses; using Xunit; diff --git a/AgileMapper.UnitTests.NonParallel/SimpleTypeConversion/WhenConvertingToStrings.cs b/AgileMapper.UnitTests.NonParallel/SimpleTypeConversion/WhenConvertingToStrings.cs index 11dd821a7..3d979f81b 100644 --- a/AgileMapper.UnitTests.NonParallel/SimpleTypeConversion/WhenConvertingToStrings.cs +++ b/AgileMapper.UnitTests.NonParallel/SimpleTypeConversion/WhenConvertingToStrings.cs @@ -3,7 +3,7 @@ using System; using System.Globalization; using Common; - using TestClasses; + using Common.TestClasses; using Xunit; public class WhenConvertingToStrings diff --git a/AgileMapper.UnitTests.NonParallel/WhenValidatingMappings.cs b/AgileMapper.UnitTests.NonParallel/WhenValidatingMappings.cs index 2f7f53dbe..c0f93c7e5 100644 --- a/AgileMapper.UnitTests.NonParallel/WhenValidatingMappings.cs +++ b/AgileMapper.UnitTests.NonParallel/WhenValidatingMappings.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.NonParallel { using Common; + using Common.TestClasses; using TestClasses; using Validation; using Xunit; diff --git a/AgileMapper.UnitTests.NonParallel/WhenViewingMappingPlans.cs b/AgileMapper.UnitTests.NonParallel/WhenViewingMappingPlans.cs index 1d6220acb..887551531 100644 --- a/AgileMapper.UnitTests.NonParallel/WhenViewingMappingPlans.cs +++ b/AgileMapper.UnitTests.NonParallel/WhenViewingMappingPlans.cs @@ -1,6 +1,8 @@ namespace AgileObjects.AgileMapper.UnitTests.NonParallel { + using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using TestClasses; using Xunit; @@ -27,7 +29,7 @@ public void ShouldShowAllCachedMappingPlansViaTheStaticApi() Mapper.GetPlanFor().ToANew(); Mapper.GetPlansFor(new MegaProduct()).To(); - var plan = Mapper.GetPlansInCache(); + string plan = Mapper.GetPlansInCache(); plan.ShouldContain("MysteryCustomer -> MysteryCustomerViewModel"); plan.ShouldContain("MegaProduct -> ProductDtoMega"); @@ -47,7 +49,7 @@ public void ShouldShowAllCachedMappingPlanExpressionsViaTheStaticApi() var plan = Mapper.GetPlanExpressionsInCache(); - plan.ShouldNotBeNull(); + plan.ShouldNotBeNull().Any().ShouldBeTrue(); }); } } diff --git a/AgileMapper.UnitTests.Orms.Ef5.LocalDb/AgileMapper.UnitTests.Orms.Ef5.LocalDb.csproj b/AgileMapper.UnitTests.Orms.Ef5.LocalDb/AgileMapper.UnitTests.Orms.Ef5.LocalDb.csproj index a34ec4c00..4a37aa76c 100644 --- a/AgileMapper.UnitTests.Orms.Ef5.LocalDb/AgileMapper.UnitTests.Orms.Ef5.LocalDb.csproj +++ b/AgileMapper.UnitTests.Orms.Ef5.LocalDb/AgileMapper.UnitTests.Orms.Ef5.LocalDb.csproj @@ -2,7 +2,6 @@ net461 - 8.0 true AgileObjects.AgileMapper.UnitTests.Orms.Ef5.LocalDb AgileObjects.AgileMapper.UnitTests.Orms.Ef5.LocalDb diff --git a/AgileMapper.UnitTests.Orms.Ef5/AgileMapper.UnitTests.Orms.Ef5.csproj b/AgileMapper.UnitTests.Orms.Ef5/AgileMapper.UnitTests.Orms.Ef5.csproj index 9156466ca..32d6274c0 100644 --- a/AgileMapper.UnitTests.Orms.Ef5/AgileMapper.UnitTests.Orms.Ef5.csproj +++ b/AgileMapper.UnitTests.Orms.Ef5/AgileMapper.UnitTests.Orms.Ef5.csproj @@ -2,7 +2,6 @@ net461 - 8.0 true AgileObjects.AgileMapper.UnitTests.Orms.Ef5 AgileObjects.AgileMapper.UnitTests.Orms.Ef5 @@ -16,7 +15,7 @@ - + diff --git a/AgileMapper.UnitTests.Orms.Ef6.LocalDb/AgileMapper.UnitTests.Orms.Ef6.LocalDb.csproj b/AgileMapper.UnitTests.Orms.Ef6.LocalDb/AgileMapper.UnitTests.Orms.Ef6.LocalDb.csproj index 8f1068748..519a404a7 100644 --- a/AgileMapper.UnitTests.Orms.Ef6.LocalDb/AgileMapper.UnitTests.Orms.Ef6.LocalDb.csproj +++ b/AgileMapper.UnitTests.Orms.Ef6.LocalDb/AgileMapper.UnitTests.Orms.Ef6.LocalDb.csproj @@ -2,7 +2,6 @@ net461 - 8.0 true AgileObjects.AgileMapper.UnitTests.Orms.Ef6.LocalDb AgileObjects.AgileMapper.UnitTests.Orms.Ef6.LocalDb diff --git a/AgileMapper.UnitTests.Orms.Ef6/AgileMapper.UnitTests.Orms.Ef6.csproj b/AgileMapper.UnitTests.Orms.Ef6/AgileMapper.UnitTests.Orms.Ef6.csproj index 3b471b0e4..1409e233b 100644 --- a/AgileMapper.UnitTests.Orms.Ef6/AgileMapper.UnitTests.Orms.Ef6.csproj +++ b/AgileMapper.UnitTests.Orms.Ef6/AgileMapper.UnitTests.Orms.Ef6.csproj @@ -2,7 +2,6 @@ net461 - 8.0 true AgileObjects.AgileMapper.UnitTests.Orms.Ef6 AgileObjects.AgileMapper.UnitTests.Orms.Ef6 @@ -16,7 +15,7 @@ - + diff --git a/AgileMapper.UnitTests.Orms.EfCore1/AgileMapper.UnitTests.Orms.EfCore1.csproj b/AgileMapper.UnitTests.Orms.EfCore1/AgileMapper.UnitTests.Orms.EfCore1.csproj index 72b747f3d..5f6515da5 100644 --- a/AgileMapper.UnitTests.Orms.EfCore1/AgileMapper.UnitTests.Orms.EfCore1.csproj +++ b/AgileMapper.UnitTests.Orms.EfCore1/AgileMapper.UnitTests.Orms.EfCore1.csproj @@ -2,8 +2,6 @@ netcoreapp1.0 - 1.1.13 - 8.0 AgileObjects.AgileMapper.UnitTests.Orms.EfCore1 AgileObjects.AgileMapper.UnitTests.Orms.EfCore1 true diff --git a/AgileMapper.UnitTests.Orms.EfCore2/AgileMapper.UnitTests.Orms.EfCore2.csproj b/AgileMapper.UnitTests.Orms.EfCore2/AgileMapper.UnitTests.Orms.EfCore2.csproj index 12fd2962a..dc055819c 100644 --- a/AgileMapper.UnitTests.Orms.EfCore2/AgileMapper.UnitTests.Orms.EfCore2.csproj +++ b/AgileMapper.UnitTests.Orms.EfCore2/AgileMapper.UnitTests.Orms.EfCore2.csproj @@ -1,9 +1,7 @@  - netcoreapp2.2 - 2.2.7 - 8.0 + netcoreapp2.1 AgileObjects.AgileMapper.UnitTests.Orms.EfCore2 AgileObjects.AgileMapper.UnitTests.Orms.EfCore2 true diff --git a/AgileMapper.UnitTests.Orms/AgileMapper.UnitTests.Orms.csproj b/AgileMapper.UnitTests.Orms/AgileMapper.UnitTests.Orms.csproj index 51585c10e..2572eb1f9 100644 --- a/AgileMapper.UnitTests.Orms/AgileMapper.UnitTests.Orms.csproj +++ b/AgileMapper.UnitTests.Orms/AgileMapper.UnitTests.Orms.csproj @@ -2,7 +2,6 @@ net461;netstandard1.3 - 8.0 AgileObjects.AgileMapper.UnitTests.Orms AgileObjects.AgileMapper.UnitTests.Orms full @@ -14,7 +13,7 @@ - + diff --git a/AgileMapper.UnitTests.Orms/WhenViewingProjectionPlans.cs b/AgileMapper.UnitTests.Orms/WhenViewingProjectionPlans.cs index eaa15dea9..8727dd8de 100644 --- a/AgileMapper.UnitTests.Orms/WhenViewingProjectionPlans.cs +++ b/AgileMapper.UnitTests.Orms/WhenViewingProjectionPlans.cs @@ -56,7 +56,7 @@ public Task ShouldReturnCachedQueryProjectionPlansInAllCachedPlans() mapper.GetPlanForProjecting(Context.StringItems).To(); mapper.GetPlanForProjecting(Context.Persons).To(); - var allPlans = mapper.GetPlansInCache(); + string allPlans = mapper.GetPlansInCache(); allPlans.ShouldContain("IQueryable -> IQueryable"); allPlans.ShouldContain("IQueryable -> IQueryable"); diff --git a/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj b/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj index d22a0af49..0eabf13ac 100644 --- a/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj +++ b/AgileMapper.UnitTests/AgileMapper.UnitTests.csproj @@ -2,7 +2,6 @@ net461 - 8.0 AgileObjects.AgileMapper.UnitTests AgileObjects.AgileMapper.UnitTests true @@ -20,8 +19,8 @@ - - + + all diff --git a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringConstructorDataSources.cs b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringConstructorDataSources.cs index 3567c2332..4f98b6b01 100644 --- a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringConstructorDataSources.cs +++ b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringConstructorDataSources.cs @@ -3,6 +3,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Configuration.DataSources using System; using AgileMapper.Extensions; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringDataSourcesIncorrectly.cs b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringDataSourcesIncorrectly.cs index 318a7061f..c703749bd 100644 --- a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringDataSourcesIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringDataSourcesIncorrectly.cs @@ -5,6 +5,7 @@ using System.Linq; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringMatcherDataSources.cs b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringMatcherDataSources.cs index b92d8a2ed..6e7672c86 100644 --- a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringMatcherDataSources.cs +++ b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringMatcherDataSources.cs @@ -2,7 +2,7 @@ { using System; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringMatcherDataSourcesIncorrectly.cs b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringMatcherDataSourcesIncorrectly.cs index 9903ff4bf..d25eabbdd 100644 --- a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringMatcherDataSourcesIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringMatcherDataSourcesIncorrectly.cs @@ -2,7 +2,7 @@ { using AgileMapper.Configuration; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringReverseDataSources.cs b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringReverseDataSources.cs index 1092b49a1..6215fabb3 100644 --- a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringReverseDataSources.cs +++ b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringReverseDataSources.cs @@ -2,6 +2,7 @@ { using System; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringReverseDataSourcesIncorrectly.cs b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringReverseDataSourcesIncorrectly.cs index 31a8be12f..11aa2c148 100644 --- a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringReverseDataSourcesIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringReverseDataSourcesIncorrectly.cs @@ -3,6 +3,7 @@ using System; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringSequentialDataSources.cs b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringSequentialDataSources.cs index ea27be4de..91e556e24 100644 --- a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringSequentialDataSources.cs +++ b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringSequentialDataSources.cs @@ -2,7 +2,7 @@ { using AgileMapper.Extensions.Internal; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringSequentialDataSourcesIncorrectly.cs b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringSequentialDataSourcesIncorrectly.cs index a39f17774..744df6e15 100644 --- a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringSequentialDataSourcesIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringSequentialDataSourcesIncorrectly.cs @@ -3,7 +3,7 @@ using System; using AgileMapper.Configuration; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; using static WhenConfiguringSequentialDataSources; diff --git a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringToTargetDataSources.cs b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringToTargetDataSources.cs index 046e32fea..748cab126 100644 --- a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringToTargetDataSources.cs +++ b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringToTargetDataSources.cs @@ -5,6 +5,7 @@ using System.Linq; using AgileMapper.Extensions; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringToTargetDataSourcesIncorrectly.cs b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringToTargetDataSourcesIncorrectly.cs index fd3c88f34..f1c7bb58d 100644 --- a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringToTargetDataSourcesIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringToTargetDataSourcesIncorrectly.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringToTargetInsteadDataSources.cs b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringToTargetInsteadDataSources.cs index a59e01967..5ee982755 100644 --- a/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringToTargetInsteadDataSources.cs +++ b/AgileMapper.UnitTests/Configuration/DataSources/WhenConfiguringToTargetInsteadDataSources.cs @@ -5,7 +5,7 @@ using System.Linq; using AgileMapper.Extensions; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Configuration/Dictionaries/WhenConfiguringDictionaryMappingIncorrectly.cs b/AgileMapper.UnitTests/Configuration/Dictionaries/WhenConfiguringDictionaryMappingIncorrectly.cs index 9bc90a327..fc72bee42 100644 --- a/AgileMapper.UnitTests/Configuration/Dictionaries/WhenConfiguringDictionaryMappingIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/Dictionaries/WhenConfiguringDictionaryMappingIncorrectly.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/Dictionaries/WhenConfiguringNestedDictionaryMapping.cs b/AgileMapper.UnitTests/Configuration/Dictionaries/WhenConfiguringNestedDictionaryMapping.cs index 4a0f4f5aa..35c34f2a1 100644 --- a/AgileMapper.UnitTests/Configuration/Dictionaries/WhenConfiguringNestedDictionaryMapping.cs +++ b/AgileMapper.UnitTests/Configuration/Dictionaries/WhenConfiguringNestedDictionaryMapping.cs @@ -2,6 +2,7 @@ { using System.Collections.Generic; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/Dictionaries/WhenConfiguringSourceDictionaryMapping.cs b/AgileMapper.UnitTests/Configuration/Dictionaries/WhenConfiguringSourceDictionaryMapping.cs index e0f6ef6a1..2da84b63b 100644 --- a/AgileMapper.UnitTests/Configuration/Dictionaries/WhenConfiguringSourceDictionaryMapping.cs +++ b/AgileMapper.UnitTests/Configuration/Dictionaries/WhenConfiguringSourceDictionaryMapping.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringCallbacksInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringCallbacksInline.cs index 4e1ece31f..bffc03864 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringCallbacksInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringCallbacksInline.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using AgileMapper.Members; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringConstructorDataSourcesInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringConstructorDataSourcesInline.cs index 0a5c24bbe..31c0996c1 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringConstructorDataSourcesInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringConstructorDataSourcesInline.cs @@ -2,6 +2,7 @@ { using System; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringDataSourcesInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringDataSourcesInline.cs index 7ea4ea930..b3a19169d 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringDataSourcesInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringDataSourcesInline.cs @@ -5,6 +5,7 @@ using AgileMapper.Extensions; using AgileMapper.Members; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using NetStandardPolyfills; diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringDataSourcesInlineIncorrectly.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringDataSourcesInlineIncorrectly.cs index 9371b8085..e43c9747d 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringDataSourcesInlineIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringDataSourcesInlineIncorrectly.cs @@ -3,6 +3,7 @@ using System; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringDerivedTypesInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringDerivedTypesInline.cs index 405697830..e4eb54db1 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringDerivedTypesInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringDerivedTypesInline.cs @@ -2,6 +2,7 @@ { using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringNameMatchingInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringNameMatchingInline.cs index 43c673eea..75221393f 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringNameMatchingInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringNameMatchingInline.cs @@ -2,7 +2,7 @@ { using AgileMapper.Configuration; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringObjectCreationInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringObjectCreationInline.cs index 432641cf7..7f1f20cb7 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringObjectCreationInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringObjectCreationInline.cs @@ -3,6 +3,7 @@ using System; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringObjectMappingInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringObjectMappingInline.cs index c948663bb..586954197 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringObjectMappingInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringObjectMappingInline.cs @@ -7,7 +7,7 @@ using AgileMapper.Extensions.Internal; using Api.Configuration; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringObjectTrackingInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringObjectTrackingInline.cs index 6883eede1..aa68256ca 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringObjectTrackingInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringObjectTrackingInline.cs @@ -4,6 +4,7 @@ using System.Linq; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; @@ -109,9 +110,9 @@ public void ShouldSupportInlineIdentityIntegrityWithGlobalDisabledObjectTracking [Fact] public void ShouldErrorIfIdentityIntegrityAndDisabledObjectTrackingConfiguredInline() { - using (var mapper = Mapper.CreateNew()) + var configEx = Should.Throw(() => { - var configEx = Should.Throw(() => + using (var mapper = Mapper.CreateNew()) { mapper.DeepClone( new[] { new Customer { Name = "BOOM" } }, @@ -119,20 +120,20 @@ public void ShouldErrorIfIdentityIntegrityAndDisabledObjectTrackingConfiguredInl .MaintainIdentityIntegrity() .And .DisableObjectTracking()); - }); + } + }); - configEx.Message.ShouldContain("Object tracking cannot be disabled"); - configEx.Message.ShouldContain("Customer[] -> Customer[]"); - configEx.Message.ShouldContain("with identity integrity configured"); - } + configEx.Message.ShouldContain("Object tracking cannot be disabled"); + configEx.Message.ShouldContain("Customer[] -> Customer[]"); + configEx.Message.ShouldContain("with identity integrity configured"); } [Fact] public void ShouldErrorIfDisabledObjectTrackingAndIdentityIntegrityConfiguredInline() { - using (var mapper = Mapper.CreateNew()) + var configEx = Should.Throw(() => { - var configEx = Should.Throw(() => + using (var mapper = Mapper.CreateNew()) { mapper.DeepClone( new[] { new Customer { Name = "BOOM" } }, @@ -140,12 +141,12 @@ public void ShouldErrorIfDisabledObjectTrackingAndIdentityIntegrityConfiguredInl .DisableObjectTracking() .And .MaintainIdentityIntegrity()); - }); + } + }); - configEx.Message.ShouldContain("Identity integrity cannot be configured"); - configEx.Message.ShouldContain("Customer[] -> Customer[]"); - configEx.Message.ShouldContain("with object tracking disabled"); - } + configEx.Message.ShouldContain("Identity integrity cannot be configured"); + configEx.Message.ShouldContain("Customer[] -> Customer[]"); + configEx.Message.ShouldContain("with object tracking disabled"); } } } diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringStringFormattingInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringStringFormattingInline.cs index c923a849a..6980390eb 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringStringFormattingInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringStringFormattingInline.cs @@ -3,7 +3,7 @@ using System; using AgileMapper.Configuration; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else @@ -82,7 +82,7 @@ public void ShouldErrorIfUnformattableTypeSpecifiedInline() } }); - noFormatEx.Message.ShouldContain("No ToString method"); + noFormatEx.Message.ShouldContain("No ToString() method"); } } } diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringTypeIdentifiersInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringTypeIdentifiersInline.cs index b060c15e0..164ec7b65 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringTypeIdentifiersInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenConfiguringTypeIdentifiersInline.cs @@ -5,6 +5,7 @@ using System.Linq; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringMembersInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringMembersInline.cs index 77e82307d..b9ba73009 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringMembersInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringMembersInline.cs @@ -3,6 +3,7 @@ using System; using Api.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringMembersInlineIncorrectly.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringMembersInlineIncorrectly.cs index 25fa53df5..7e3f96da5 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringMembersInlineIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringMembersInlineIncorrectly.cs @@ -2,7 +2,7 @@ { using AgileMapper.Configuration; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringSourceMemberInlineIncorrectly.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringSourceMemberInlineIncorrectly.cs index ca466a297..ce130565e 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringSourceMemberInlineIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringSourceMemberInlineIncorrectly.cs @@ -2,7 +2,7 @@ { using AgileMapper.Configuration; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringSourceMembersByValueFilterInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringSourceMembersByValueFilterInline.cs index 8fd36c240..428981469 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringSourceMembersByValueFilterInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringSourceMembersByValueFilterInline.cs @@ -6,6 +6,7 @@ using AgileMapper.Extensions.Internal; using AgileObjects.AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringSourceMembersInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringSourceMembersInline.cs index b4cf2f8d5..0477170f6 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringSourceMembersInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenIgnoringSourceMembersInline.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Configuration.Inline { using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/Inline/WhenMappingToNullInline.cs b/AgileMapper.UnitTests/Configuration/Inline/WhenMappingToNullInline.cs index 16298a786..6c9086e4b 100644 --- a/AgileMapper.UnitTests/Configuration/Inline/WhenMappingToNullInline.cs +++ b/AgileMapper.UnitTests/Configuration/Inline/WhenMappingToNullInline.cs @@ -3,6 +3,7 @@ using AgileMapper.Configuration; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembers.cs b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembers.cs index 00bffea48..2b207f999 100644 --- a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembers.cs +++ b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembers.cs @@ -6,6 +6,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Configuration.MemberIgnores using AgileMapper.Configuration; using AgileMapper.Configuration.MemberIgnores; using Common; + using Common.TestClasses; using NetStandardPolyfills; using TestClasses; #if !NET35 diff --git a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembersByFilter.cs b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembersByFilter.cs index 46bf20eb6..31e7fa6d3 100644 --- a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembersByFilter.cs +++ b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembersByFilter.cs @@ -3,6 +3,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Configuration.MemberIgnores using System; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using NetStandardPolyfills; using TestClasses; #if !NET35 diff --git a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembersByGlobalFilter.cs b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembersByGlobalFilter.cs index 6212f6930..23cab825e 100644 --- a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembersByGlobalFilter.cs +++ b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembersByGlobalFilter.cs @@ -3,6 +3,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Configuration.MemberIgnores using System; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using NetStandardPolyfills; using TestClasses; #if !NET35 diff --git a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembersIncorrectly.cs b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembersIncorrectly.cs index f60bc7c79..d1c1055db 100644 --- a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembersIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringMembersIncorrectly.cs @@ -2,6 +2,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Configuration.MemberIgnores { using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembers.cs b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembers.cs index 088937036..5ffd6a187 100644 --- a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembers.cs +++ b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembers.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersByFilter.cs b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersByFilter.cs index 7dc509980..0ce9ada74 100644 --- a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersByFilter.cs +++ b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersByFilter.cs @@ -3,6 +3,7 @@ using System; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using NetStandardPolyfills; using TestClasses; #if !NET35 diff --git a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersByGlobalFilter.cs b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersByGlobalFilter.cs index 7caf2998c..46eb53721 100644 --- a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersByGlobalFilter.cs +++ b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersByGlobalFilter.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Configuration.MemberIgnores { using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersByValueFilter.cs b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersByValueFilter.cs index bbb6152b7..682e7d349 100644 --- a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersByValueFilter.cs +++ b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersByValueFilter.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersIncorrectly.cs b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersIncorrectly.cs index 6bf307f70..cfeaf5efe 100644 --- a/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/MemberIgnores/WhenIgnoringSourceMembersIncorrectly.cs @@ -2,6 +2,7 @@ { using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/WhenApplyingMapperConfigurations.cs b/AgileMapper.UnitTests/Configuration/WhenApplyingMapperConfigurations.cs index ec5ff4958..1833c4277 100644 --- a/AgileMapper.UnitTests/Configuration/WhenApplyingMapperConfigurations.cs +++ b/AgileMapper.UnitTests/Configuration/WhenApplyingMapperConfigurations.cs @@ -5,9 +5,9 @@ using System.Linq; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using MoreTestClasses; using NetStandardPolyfills; - using TestClasses; using Testing; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringDerivedTypes.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringDerivedTypes.cs index 278a36acf..698f9075f 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringDerivedTypes.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringDerivedTypes.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringDerivedTypesIncorrectly.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringDerivedTypesIncorrectly.cs index 45816b133..2b116e6b2 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringDerivedTypesIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringDerivedTypesIncorrectly.cs @@ -4,6 +4,7 @@ using System.Reflection; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; using static WhenConfiguringDerivedTypes; #if !NET35 diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringEntityMapping.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringEntityMapping.cs index c15b593b6..06c7b5ab3 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringEntityMapping.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringEntityMapping.cs @@ -3,6 +3,7 @@ using System; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringExceptionHandling.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringExceptionHandling.cs index 039351391..58b1d7589 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringExceptionHandling.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringExceptionHandling.cs @@ -2,6 +2,7 @@ { using System; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringNameMatching.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringNameMatching.cs index 2183e6b70..cb5e1397a 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringNameMatching.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringNameMatching.cs @@ -5,7 +5,7 @@ using AgileMapper.Configuration; using AgileMapper.Extensions.Internal; using Common; - using TestClasses; + using Common.TestClasses; using static System.Environment; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreation.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreation.cs index 7feb448ef..f818fc267 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreation.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreation.cs @@ -6,6 +6,7 @@ using System.Linq; using AgileMapper.Members; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreationCallbacks.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreationCallbacks.cs index d27a1ff4b..e838f4234 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreationCallbacks.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreationCallbacks.cs @@ -7,6 +7,7 @@ using System.Linq; using AgileMapper.Members; using Common; + using Common.TestClasses; using ReadableExpressions.Extensions; using TestClasses; #if !NET35 diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreationIncorrectly.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreationIncorrectly.cs index bfcac36ee..b9d951ecc 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreationIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectCreationIncorrectly.cs @@ -3,6 +3,7 @@ using System; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectMapping.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectMapping.cs index 6e168d77d..ebd82f4fe 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectMapping.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectMapping.cs @@ -5,6 +5,7 @@ using System.Linq; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectMappingIncorrectly.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectMappingIncorrectly.cs index b581a6b04..6866de062 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectMappingIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectMappingIncorrectly.cs @@ -3,6 +3,7 @@ using System; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectTracking.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectTracking.cs index 461c1ef1b..c6dd2a443 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectTracking.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectTracking.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectTrackingIncorrectly.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectTrackingIncorrectly.cs index 6164042ae..e07d3a4f6 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectTrackingIncorrectly.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringObjectTrackingIncorrectly.cs @@ -2,6 +2,7 @@ { using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; @@ -15,157 +16,154 @@ public class WhenConfiguringObjectTrackingIncorrectly [Fact] public void ShouldErrorIfGlobalIdentityIntegrityConfiguredWithDisabledObjectTracking() { - using (var mapper = Mapper.CreateNew()) + var configEx = Should.Throw(() => { - mapper.WhenMapping.DisableObjectTracking(); - - var configEx = Should.Throw(() => + using (var mapper = Mapper.CreateNew()) { + mapper.WhenMapping.DisableObjectTracking(); + mapper.WhenMapping.MaintainIdentityIntegrity(); - }); + } + }); - configEx.Message.ShouldContain("Identity integrity cannot be configured"); - configEx.Message.ShouldContain("global object tracking disabled"); - } + configEx.Message.ShouldContain("Identity integrity cannot be configured"); + configEx.Message.ShouldContain("global object tracking disabled"); } [Fact] public void ShouldErrorIfGlobalIdentityIntegrityConfiguredTwice() { - using (var mapper = Mapper.CreateNew()) + var configEx = Should.Throw(() => { - mapper.WhenMapping.MaintainIdentityIntegrity(); - - var configEx = Should.Throw(() => + using (var mapper = Mapper.CreateNew()) { mapper.WhenMapping.MaintainIdentityIntegrity(); - }); + mapper.WhenMapping.MaintainIdentityIntegrity(); + } + }); - configEx.Message.ShouldContain("Identity integrity is already configured"); - } + configEx.Message.ShouldContain("Identity integrity is already configured"); } [Fact] public void ShouldErrorIfIdentityIntegrityConfiguredTwice() { - using (var mapper = Mapper.CreateNew()) + var configEx = Should.Throw(() => { - mapper.WhenMapping - .From() - .To() - .MaintainIdentityIntegrity(); - - var configEx = Should.Throw(() => + using (var mapper = Mapper.CreateNew()) { mapper.WhenMapping .From() .To() .MaintainIdentityIntegrity(); - }); - configEx.Message.ShouldContain("Identity integrity is already configured"); - configEx.Message.ShouldContain("Product -> ProductDto"); - } + mapper.WhenMapping + .From() + .To() + .MaintainIdentityIntegrity(); + } + }); + + configEx.Message.ShouldContain("Identity integrity is already configured"); + configEx.Message.ShouldContain("Product -> ProductDto"); } [Fact] public void ShouldErrorIfRedundantIdentityIntegrityConfigured() { - using (var mapper = Mapper.CreateNew()) + var configEx = Should.Throw(() => { - mapper.WhenMapping - .From() - .To() - .MaintainIdentityIntegrity(); - - var configEx = Should.Throw(() => + using (var mapper = Mapper.CreateNew()) { + mapper.WhenMapping + .From() + .To() + .MaintainIdentityIntegrity(); + mapper.WhenMapping .From() .To() .MaintainIdentityIntegrity(); - }); + } + }); - configEx.Message.ShouldContain("Identity integrity is already configured"); - configEx.Message.ShouldContain("Product -> ProductDto"); - } + configEx.Message.ShouldContain("Identity integrity is already configured"); + configEx.Message.ShouldContain("Product -> ProductDto"); } [Fact] public void ShouldErrorIfGlobalObjectTrackingDisabledWithIdentityIntegrityConfigured() { - using (var mapper = Mapper.CreateNew()) + var configEx = Should.Throw(() => { - mapper.WhenMapping.MaintainIdentityIntegrity(); - - var configEx = Should.Throw(() => + using (var mapper = Mapper.CreateNew()) { + mapper.WhenMapping.MaintainIdentityIntegrity(); mapper.WhenMapping.DisableObjectTracking(); - }); + } + }); - configEx.Message.ShouldContain("Object tracking cannot be disabled"); - configEx.Message.ShouldContain("global identity integrity configured"); - } + configEx.Message.ShouldContain("Object tracking cannot be disabled"); + configEx.Message.ShouldContain("global identity integrity configured"); } [Fact] public void ShouldErrorIfGlobalObjectTrackingDisabledTwice() { - using (var mapper = Mapper.CreateNew()) + var configEx = Should.Throw(() => { - mapper.WhenMapping.DisableObjectTracking(); - - var configEx = Should.Throw(() => + using (var mapper = Mapper.CreateNew()) { mapper.WhenMapping.DisableObjectTracking(); - }); + mapper.WhenMapping.DisableObjectTracking(); + } + }); - configEx.Message.ShouldContain("Object tracking is already disabled"); - } + configEx.Message.ShouldContain("Object tracking is already disabled"); } [Fact] public void ShouldErrorIfDuplicateObjectTrackingDisabled() { - using (var mapper = Mapper.CreateNew()) + var configEx = Should.Throw(() => { - mapper.WhenMapping - .From().To() - .DisableObjectTracking(); - - var configEx = Should.Throw(() => + using (var mapper = Mapper.CreateNew()) { + mapper.WhenMapping + .From().To() + .DisableObjectTracking(); + mapper.WhenMapping .From() .To() .DisableObjectTracking(); - }); + } + }); - configEx.Message.ShouldContain("Object tracking is already disabled"); - configEx.Message.ShouldContain("PersonViewModel -> Person"); - } + configEx.Message.ShouldContain("Object tracking is already disabled"); + configEx.Message.ShouldContain("PersonViewModel -> Person"); } [Fact] public void ShouldErrorIfRedundantObjectTrackingDisabled() { - using (var mapper = Mapper.CreateNew()) + var configEx = Should.Throw(() => { - mapper.WhenMapping - .To() - .DisableObjectTracking(); - - var configEx = Should.Throw(() => + using (var mapper = Mapper.CreateNew()) { + mapper.WhenMapping + .To() + .DisableObjectTracking(); + mapper.WhenMapping .From() .To() .DisableObjectTracking(); - }); + } + }); - configEx.Message.ShouldContain("Object tracking is already disabled"); - configEx.Message.ShouldContain("to Person"); - } + configEx.Message.ShouldContain("Object tracking is already disabled"); + configEx.Message.ShouldContain("to Person"); } } } diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringSimpleTypeCreation.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringSimpleTypeCreation.cs index 73e2395bc..1466835f0 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringSimpleTypeCreation.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringSimpleTypeCreation.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/WhenConfiguringStringFormatting.cs b/AgileMapper.UnitTests/Configuration/WhenConfiguringStringFormatting.cs index 6c1395a3f..c0cbc2c09 100644 --- a/AgileMapper.UnitTests/Configuration/WhenConfiguringStringFormatting.cs +++ b/AgileMapper.UnitTests/Configuration/WhenConfiguringStringFormatting.cs @@ -3,7 +3,7 @@ using System; using AgileMapper.Configuration; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else @@ -86,7 +86,7 @@ public void ShouldErrorIfUnformattableTypeSpecified() } }); - noFormatEx.Message.ShouldContain("No ToString method"); + noFormatEx.Message.ShouldContain("No ToString() method"); } } } diff --git a/AgileMapper.UnitTests/Configuration/WhenMappingToNull.cs b/AgileMapper.UnitTests/Configuration/WhenMappingToNull.cs index 87087d4ff..f6eb1a8a0 100644 --- a/AgileMapper.UnitTests/Configuration/WhenMappingToNull.cs +++ b/AgileMapper.UnitTests/Configuration/WhenMappingToNull.cs @@ -7,6 +7,7 @@ using AgileMapper.Configuration; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Configuration/WhenResolvingServices.cs b/AgileMapper.UnitTests/Configuration/WhenResolvingServices.cs index a59a13443..d74eb11e5 100644 --- a/AgileMapper.UnitTests/Configuration/WhenResolvingServices.cs +++ b/AgileMapper.UnitTests/Configuration/WhenResolvingServices.cs @@ -5,7 +5,7 @@ using AgileMapper.Configuration; using AgileMapper.Extensions; using Common; - using TestClasses; + using Common.TestClasses; #if NETCOREAPP using Microsoft.Extensions.DependencyInjection; #endif diff --git a/AgileMapper.UnitTests/Configuration/WhenViewingMappingPlans.cs b/AgileMapper.UnitTests/Configuration/WhenViewingMappingPlans.cs index 73a6bf857..566fe219c 100644 --- a/AgileMapper.UnitTests/Configuration/WhenViewingMappingPlans.cs +++ b/AgileMapper.UnitTests/Configuration/WhenViewingMappingPlans.cs @@ -101,13 +101,12 @@ public void ShouldShowMapChildObjectCalls() .Map((pp, ptf) => pp.Value) .To(ptf => ptf.Value1); - string plan = mapper .GetPlanFor>() .ToANew>(); plan.ShouldContain("// Map PublicProperty -> PublicTwoFields"); - plan.ShouldContain(".Value1 = ppsToPtfsoData.Source.Value"); + plan.ShouldContain(".Value1 = sppToSoptfData.Source.Value"); plan.ShouldContain("// No data sources for Value2"); } } diff --git a/AgileMapper.UnitTests/Dictionaries/WhenFlatteningToDictionaries.cs b/AgileMapper.UnitTests/Dictionaries/WhenFlatteningToDictionaries.cs index 566fcc3c2..e8ad031e8 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenFlatteningToDictionaries.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenFlatteningToDictionaries.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesOnToComplexTypes.cs b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesOnToComplexTypes.cs index 2e1017727..c7d8ae340 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesOnToComplexTypes.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesOnToComplexTypes.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesOnToEnumerableMembers.cs b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesOnToEnumerableMembers.cs index 890abdc69..be7766916 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesOnToEnumerableMembers.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesOnToEnumerableMembers.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesOverComplexTypes.cs b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesOverComplexTypes.cs index 2afd5332f..edae53dda 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesOverComplexTypes.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesOverComplexTypes.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesToNewComplexTypes.cs b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesToNewComplexTypes.cs index 841812127..bfcfdf5b3 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesToNewComplexTypes.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesToNewComplexTypes.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesToNewEnumerableMembers.cs b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesToNewEnumerableMembers.cs index 8cc49b562..f1ad12300 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesToNewEnumerableMembers.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesToNewEnumerableMembers.cs @@ -5,6 +5,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Dictionaries using System.Collections.ObjectModel; using System.Linq; using Common; + using Common.TestClasses; #if !NETCOREAPP1_0 && !NET35 using Microsoft.Extensions.Primitives; #endif diff --git a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesToNewEnumerables.cs b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesToNewEnumerables.cs index c29afe94e..9b7df15a3 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesToNewEnumerables.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionariesToNewEnumerables.cs @@ -4,6 +4,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Dictionaries using System.Collections.Generic; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionaryMembers.cs b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionaryMembers.cs index a4d2393f7..900fa8581 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionaryMembers.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenMappingFromDictionaryMembers.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Dictionaries/WhenMappingOnToDictionaries.cs b/AgileMapper.UnitTests/Dictionaries/WhenMappingOnToDictionaries.cs index 31e87aff7..db810c95c 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenMappingOnToDictionaries.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenMappingOnToDictionaries.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Dictionaries/WhenMappingOnToDictionaryMembers.cs b/AgileMapper.UnitTests/Dictionaries/WhenMappingOnToDictionaryMembers.cs index 9af6a086f..95b35e524 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenMappingOnToDictionaryMembers.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenMappingOnToDictionaryMembers.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Dictionaries/WhenMappingOverDictionaries.cs b/AgileMapper.UnitTests/Dictionaries/WhenMappingOverDictionaries.cs index f34f9192e..8770ccfc6 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenMappingOverDictionaries.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenMappingOverDictionaries.cs @@ -5,6 +5,7 @@ using System.Collections.ObjectModel; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Dictionaries/WhenMappingOverDictionaryMembers.cs b/AgileMapper.UnitTests/Dictionaries/WhenMappingOverDictionaryMembers.cs index 613970838..cd3332277 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenMappingOverDictionaryMembers.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenMappingOverDictionaryMembers.cs @@ -2,6 +2,7 @@ { using System.Collections.Generic; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Dictionaries/WhenMappingToNewDictionaries.cs b/AgileMapper.UnitTests/Dictionaries/WhenMappingToNewDictionaries.cs index 373e78ee9..efb458674 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenMappingToNewDictionaries.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenMappingToNewDictionaries.cs @@ -5,6 +5,7 @@ using System.Collections.ObjectModel; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; @@ -44,6 +45,22 @@ public void ShouldMapAComplexTypeMemberToATypedDictionary() result["Value"].ShouldBeOfType(); } + [Fact] + public void ShouldMapAComplexTypeMemberToAnUntypedDictionary() + { + var source = new PublicTwoFields + { + Value1 = 123, + Value2 = new Address { Line1 = "One!" } + }; + + var result = Mapper.Map(source).ToANew>(); + + result.ShouldContainKeyAndValue("Value1", "123"); + result.ShouldContainKeyAndValue("Value2.Line1", "One!"); + result.ShouldContainKeyAndValue("Value2.Line2", null); + } + [Fact] public void ShouldMapASimpleTypeMemberToAConvertibleTypedDictionary() { diff --git a/AgileMapper.UnitTests/Dictionaries/WhenUnflatteningFromDictionaries.cs b/AgileMapper.UnitTests/Dictionaries/WhenUnflatteningFromDictionaries.cs index faf31a501..c47fa76ab 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenUnflatteningFromDictionaries.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenUnflatteningFromDictionaries.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Dictionaries/WhenViewingDictionaryMappingPlans.cs b/AgileMapper.UnitTests/Dictionaries/WhenViewingDictionaryMappingPlans.cs index 4919a6a05..c77ba1f5a 100644 --- a/AgileMapper.UnitTests/Dictionaries/WhenViewingDictionaryMappingPlans.cs +++ b/AgileMapper.UnitTests/Dictionaries/WhenViewingDictionaryMappingPlans.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; @@ -20,9 +21,9 @@ public void ShouldShowATargetObjectMappingPlan() .GetPlanFor>() .ToANew(); - plan.ShouldContain("Dictionary sourceDictionary_String_String"); - plan.ShouldContain("idKey = sourceDictionary_String_String.Keys.FirstOrDefault(key => key.MatchesKey(\"Id\""); - plan.ShouldContain("id = sourceDictionary_String_String[idKey]"); + plan.ShouldContain("Dictionary sourceStringStringDictionary"); + plan.ShouldContain("idKey = sourceStringStringDictionary.Keys.FirstOrDefault(key => key.MatchesKey(\"Id\""); + plan.ShouldContain("id = sourceStringStringDictionary[idKey]"); plan.ShouldContain("customerViewModel.Id ="); #if NET35 plan.ShouldContain("id.ToGuid()"); @@ -39,9 +40,9 @@ public void ShouldShowATargetComplexTypeCollectionMappingPlan() .ToANew>(); plan.ShouldContain("targetElementKey = \"[\" + i + \"]\""); - plan.ShouldContain("elementKeyExists = sourceDictionary_String_Object.ContainsKey(targetElementKey)"); + plan.ShouldContain("elementKeyExists = sourceStringObjectDictionary.ContainsKey(targetElementKey)"); plan.ShouldContain("var line1Key = \"[\" + i + \"].Line1\""); - plan.ShouldContain("line1 = sourceDictionary_String_Object[line1Key]"); + plan.ShouldContain("line1 = sourceStringObjectDictionary[line1Key]"); plan.ShouldContain("address.Line1 = line1.ToString()"); } @@ -52,9 +53,9 @@ public void ShouldShowASourceObjectMappingPlan() .GetPlanFor() .ToANew>(); - plan.ShouldContain("dictionary_String_Object = new Dictionary()"); - plan.ShouldContain("dictionary_String_Object[\"Name\"] = sourceMysteryCustomer.Name"); - plan.ShouldContain("dictionary_String_Object[\"Address.Line1\"] = sourceMysteryCustomer.Address.Line1;"); + plan.ShouldContain("stringObjectDictionary = new Dictionary()"); + plan.ShouldContain("stringObjectDictionary[\"Name\"] = sourceMysteryCustomer.Name"); + plan.ShouldContain("stringObjectDictionary[\"Address.Line1\"] = sourceMysteryCustomer.Address.Line1;"); } [Fact] @@ -65,8 +66,8 @@ public void ShouldShowASourceComplexTypeEnumerableMappingPlan() .ToANew>(); plan.ShouldContain("sourceMysteryCustomerViewModel = enumerator.Current as MysteryCustomerViewModel"); - plan.ShouldContain("dictionary_String_String[\"[\" + i + \"].Report\"] = sourceMysteryCustomerViewModel.Report"); - plan.ShouldContain("dictionary_String_String[\"[\" + i + \"].AddressLine1\"] = enumerator.Current.AddressLine1"); + plan.ShouldContain("stringStringDictionary[\"[\" + i + \"].Report\"] = sourceMysteryCustomerViewModel.Report"); + plan.ShouldContain("stringStringDictionary[\"[\" + i + \"].AddressLine1\"] = enumerator.Current.AddressLine1"); } } diff --git a/AgileMapper.UnitTests/Dynamics/Configuration/WhenConfiguringSourceDynamicMapping.cs b/AgileMapper.UnitTests/Dynamics/Configuration/WhenConfiguringSourceDynamicMapping.cs index fc439da46..a3cae5b40 100644 --- a/AgileMapper.UnitTests/Dynamics/Configuration/WhenConfiguringSourceDynamicMapping.cs +++ b/AgileMapper.UnitTests/Dynamics/Configuration/WhenConfiguringSourceDynamicMapping.cs @@ -7,6 +7,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Dynamics.Configuration using System.Linq.Expressions; using Api.Configuration; using Common; + using Common.TestClasses; using TestClasses; using Xunit; diff --git a/AgileMapper.UnitTests/Dynamics/WhenFlatteningToDynamics.cs b/AgileMapper.UnitTests/Dynamics/WhenFlatteningToDynamics.cs index 61d30b9d3..0458e2226 100644 --- a/AgileMapper.UnitTests/Dynamics/WhenFlatteningToDynamics.cs +++ b/AgileMapper.UnitTests/Dynamics/WhenFlatteningToDynamics.cs @@ -2,8 +2,8 @@ { using System.Collections.Generic; using Common; + using Common.TestClasses; using Microsoft.CSharp.RuntimeBinder; - using TestClasses; using Xunit; public class WhenFlatteningToDynamics diff --git a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverComplexTypeMembers.cs b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverComplexTypeMembers.cs index f52bc0c6b..b71764045 100644 --- a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverComplexTypeMembers.cs +++ b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverComplexTypeMembers.cs @@ -2,6 +2,7 @@ { using System.Dynamic; using Common; + using Common.TestClasses; using TestClasses; using Xunit; diff --git a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverComplexTypes.cs b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverComplexTypes.cs index 319931fcd..2bcba2606 100644 --- a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverComplexTypes.cs +++ b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverComplexTypes.cs @@ -3,7 +3,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Dynamics { using System.Dynamic; using Common; - using TestClasses; + using Common.TestClasses; using Xunit; public class WhenMappingFromDynamicsOverComplexTypes diff --git a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverEnumerableMembers.cs b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverEnumerableMembers.cs index 8d278e178..1a7322365 100644 --- a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverEnumerableMembers.cs +++ b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverEnumerableMembers.cs @@ -6,7 +6,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Dynamics using System.Dynamic; using System.Linq; using Common; - using TestClasses; + using Common.TestClasses; using Xunit; public class WhenMappingFromDynamicsOverEnumerableMembers diff --git a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverEnumerables.cs b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverEnumerables.cs index 1ccebfd43..7785eee15 100644 --- a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverEnumerables.cs +++ b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsOverEnumerables.cs @@ -6,6 +6,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Dynamics using System.Linq; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using TestClasses; using Xunit; diff --git a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewComplexTypeMembers.cs b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewComplexTypeMembers.cs index bf169c6a4..745779582 100644 --- a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewComplexTypeMembers.cs +++ b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewComplexTypeMembers.cs @@ -2,6 +2,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Dynamics { using System.Dynamic; + using Common.TestClasses; using TestClasses; using Xunit; diff --git a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewComplexTypes.cs b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewComplexTypes.cs index 7e853afd6..81466805e 100644 --- a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewComplexTypes.cs +++ b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewComplexTypes.cs @@ -4,6 +4,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Dynamics using System; using System.Dynamic; using Common; + using Common.TestClasses; using TestClasses; using Xunit; diff --git a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewEnumerableMembers.cs b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewEnumerableMembers.cs index afef7d3f0..a26bf359f 100644 --- a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewEnumerableMembers.cs +++ b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewEnumerableMembers.cs @@ -3,6 +3,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Dynamics { using System.Collections.Generic; using System.Dynamic; + using Common.TestClasses; using TestClasses; using Xunit; diff --git a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewEnumerables.cs b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewEnumerables.cs index 5b214bc3e..a7f5e9d03 100644 --- a/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewEnumerables.cs +++ b/AgileMapper.UnitTests/Dynamics/WhenMappingFromDynamicsToNewEnumerables.cs @@ -5,6 +5,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Dynamics using System.Collections.Generic; using System.Collections.ObjectModel; using System.Dynamic; + using Common.TestClasses; using TestClasses; using Xunit; diff --git a/AgileMapper.UnitTests/Dynamics/WhenMappingOnToDynamicMembers.cs b/AgileMapper.UnitTests/Dynamics/WhenMappingOnToDynamicMembers.cs index 155e45a1d..e27d3dfa7 100644 --- a/AgileMapper.UnitTests/Dynamics/WhenMappingOnToDynamicMembers.cs +++ b/AgileMapper.UnitTests/Dynamics/WhenMappingOnToDynamicMembers.cs @@ -4,8 +4,8 @@ using System.Collections.Generic; using System.Dynamic; using Common; + using Common.TestClasses; using Microsoft.CSharp.RuntimeBinder; - using TestClasses; using Xunit; public class WhenMappingOnToDynamicMembers diff --git a/AgileMapper.UnitTests/Dynamics/WhenMappingOverDynamicMembers.cs b/AgileMapper.UnitTests/Dynamics/WhenMappingOverDynamicMembers.cs index a82e14e51..1072f863b 100644 --- a/AgileMapper.UnitTests/Dynamics/WhenMappingOverDynamicMembers.cs +++ b/AgileMapper.UnitTests/Dynamics/WhenMappingOverDynamicMembers.cs @@ -1,7 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Dynamics { using System.Dynamic; - using TestClasses; + using Common.TestClasses; using Xunit; public class WhenMappingOverDynamicMembers diff --git a/AgileMapper.UnitTests/Dynamics/WhenMappingToNewDynamicMembers.cs b/AgileMapper.UnitTests/Dynamics/WhenMappingToNewDynamicMembers.cs index 27d586a60..28328f949 100644 --- a/AgileMapper.UnitTests/Dynamics/WhenMappingToNewDynamicMembers.cs +++ b/AgileMapper.UnitTests/Dynamics/WhenMappingToNewDynamicMembers.cs @@ -1,7 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Dynamics { using System.Dynamic; - using TestClasses; + using Common.TestClasses; using Xunit; public class WhenMappingToNewDynamicMembers diff --git a/AgileMapper.UnitTests/Dynamics/WhenMappingToNewEnumerablesOfDynamic.cs b/AgileMapper.UnitTests/Dynamics/WhenMappingToNewEnumerablesOfDynamic.cs index ec8e8d8e4..26db42b31 100644 --- a/AgileMapper.UnitTests/Dynamics/WhenMappingToNewEnumerablesOfDynamic.cs +++ b/AgileMapper.UnitTests/Dynamics/WhenMappingToNewEnumerablesOfDynamic.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; using Xunit; diff --git a/AgileMapper.UnitTests/Extensions/Internal/WhenEquatingExpressions.cs b/AgileMapper.UnitTests/Extensions/Internal/WhenEquatingExpressions.cs index 6d44a0fac..9cf51cc89 100644 --- a/AgileMapper.UnitTests/Extensions/Internal/WhenEquatingExpressions.cs +++ b/AgileMapper.UnitTests/Extensions/Internal/WhenEquatingExpressions.cs @@ -5,6 +5,7 @@ using System.Linq.Expressions; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Extensions/Internal/WhenGeneratingVariableNames.cs b/AgileMapper.UnitTests/Extensions/Internal/WhenGeneratingVariableNames.cs index 19fa7ae0e..546ff80a2 100644 --- a/AgileMapper.UnitTests/Extensions/Internal/WhenGeneratingVariableNames.cs +++ b/AgileMapper.UnitTests/Extensions/Internal/WhenGeneratingVariableNames.cs @@ -14,91 +14,15 @@ public class WhenGeneratingVariableNames { [Fact] - public void ShouldNameAShortVariableForACollectionType() + public void ShouldNameAShortCollectionTypeVariable() { - typeof(ICollection).GetShortVariableName().ShouldBe("ps"); + typeof(ICollection).GetShortVariableName().ShouldBe("pic"); } [Fact] - public void ShouldNameAMultiLetterShortVariableForACollectionType() + public void ShouldNameAMultiLetterShortCollectionTypeVariable() { - typeof(ICollection).GetShortVariableName().ShouldBe("cvms"); + typeof(ICollection).GetShortVariableName().ShouldBe("cvmic"); } - - [Fact] - public void ShouldNameAVariableForAnArrayType() - { - typeof(Box[]).GetVariableNameInCamelCase().ShouldBe("boxArray"); - } - - [Fact] - public void ShouldNameAVariableForACollectionTypeEndingInX() - { - typeof(ICollection).GetVariableNameInCamelCase().ShouldBe("boxes"); - } - - [Fact] - public void ShouldNameAVariableForAnEnumerableTypeEndingInZ() - { - typeof(IEnumerable).GetVariableNameInPascalCase().ShouldBe("Fuzzes"); - } - - [Fact] - public void ShouldNameAVariableForAnEnumerableTypeEndingInDoubleS() - { - typeof(IEnumerable).GetVariableNameInPascalCase().ShouldBe("Glasses"); - } - - [Fact] - public void ShouldNameAVariableForAListTypeEndingInCh() - { - typeof(List).GetVariableNameInCamelCase().ShouldBe("churches"); - } - - [Fact] - public void ShouldNameAVariableForAListTypeEndingInSh() - { - typeof(List).GetVariableNameInCamelCase().ShouldBe("hushes"); - } - - [Fact] - public void ShouldNameAVariableForAListTypeEndingInVowelY() - { - typeof(List).GetVariableNameInCamelCase().ShouldBe("journeys"); - } - - [Fact] - public void ShouldNameAVariableForAnIListTypeEndingInConsonantY() - { - typeof(IList).GetVariableNameInPascalCase().ShouldBe("Bodies"); - } - - [Fact] - public void ShouldNameANullableLongVariable() - { - typeof(long?).GetVariableNameInCamelCase().ShouldBe("nullableLong"); - } - - [Fact] - public void ShouldNameAnArrayOfArraysVariable() - { - typeof(int?[][]).GetVariableNameInCamelCase().ShouldBe("nullableIntArrayArray"); - } - - // ReSharper disable ClassNeverInstantiated.Local - private class Box { } - - private class Fuzz { } - - private class Glass { } - - private class Church { } - - private class Hush { } - - private class Journey { } - - private class Body { } - // ReSharper restore ClassNeverInstantiated.Local } } diff --git a/AgileMapper.UnitTests/Extensions/WhenFlatteningToQueryStringViaExtensionMethods.cs b/AgileMapper.UnitTests/Extensions/WhenFlatteningToQueryStringViaExtensionMethods.cs index 4ab88c5da..d36191ebb 100644 --- a/AgileMapper.UnitTests/Extensions/WhenFlatteningToQueryStringViaExtensionMethods.cs +++ b/AgileMapper.UnitTests/Extensions/WhenFlatteningToQueryStringViaExtensionMethods.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using AgileMapper.Extensions; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Extensions/WhenFlatteningViaExtensionMethods.cs b/AgileMapper.UnitTests/Extensions/WhenFlatteningViaExtensionMethods.cs index 3e7b796c6..39b49a13a 100644 --- a/AgileMapper.UnitTests/Extensions/WhenFlatteningViaExtensionMethods.cs +++ b/AgileMapper.UnitTests/Extensions/WhenFlatteningViaExtensionMethods.cs @@ -2,6 +2,7 @@ { using AgileMapper.Extensions; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Extensions/WhenMappingViaExtensionMethods.cs b/AgileMapper.UnitTests/Extensions/WhenMappingViaExtensionMethods.cs index f3d3869f7..24fcf4607 100644 --- a/AgileMapper.UnitTests/Extensions/WhenMappingViaExtensionMethods.cs +++ b/AgileMapper.UnitTests/Extensions/WhenMappingViaExtensionMethods.cs @@ -4,6 +4,7 @@ using System.Globalization; using AgileMapper.Extensions; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Extensions/WhenUnflatteningFromQueryStringsViaExtensionMethods.cs b/AgileMapper.UnitTests/Extensions/WhenUnflatteningFromQueryStringsViaExtensionMethods.cs index cf7dc4fc2..3b23ec1f9 100644 --- a/AgileMapper.UnitTests/Extensions/WhenUnflatteningFromQueryStringsViaExtensionMethods.cs +++ b/AgileMapper.UnitTests/Extensions/WhenUnflatteningFromQueryStringsViaExtensionMethods.cs @@ -3,7 +3,7 @@ using System; using AgileMapper.Extensions; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Extensions/WhenUnflatteningViaExtensionMethods.cs b/AgileMapper.UnitTests/Extensions/WhenUnflatteningViaExtensionMethods.cs index f47812e15..ecd82867f 100644 --- a/AgileMapper.UnitTests/Extensions/WhenUnflatteningViaExtensionMethods.cs +++ b/AgileMapper.UnitTests/Extensions/WhenUnflatteningViaExtensionMethods.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using AgileMapper.Extensions; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/MapperCloning/WhenCloningConstructorDataSources.cs b/AgileMapper.UnitTests/MapperCloning/WhenCloningConstructorDataSources.cs index 81800f48f..0bb40b5fc 100644 --- a/AgileMapper.UnitTests/MapperCloning/WhenCloningConstructorDataSources.cs +++ b/AgileMapper.UnitTests/MapperCloning/WhenCloningConstructorDataSources.cs @@ -2,6 +2,7 @@ { using System; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/MapperCloning/WhenCloningDataSources.cs b/AgileMapper.UnitTests/MapperCloning/WhenCloningDataSources.cs index f26f695f3..d76eb8355 100644 --- a/AgileMapper.UnitTests/MapperCloning/WhenCloningDataSources.cs +++ b/AgileMapper.UnitTests/MapperCloning/WhenCloningDataSources.cs @@ -2,6 +2,7 @@ { using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/MapperCloning/WhenCloningDictionarySettings.cs b/AgileMapper.UnitTests/MapperCloning/WhenCloningDictionarySettings.cs index 347f8c936..00ac63fbf 100644 --- a/AgileMapper.UnitTests/MapperCloning/WhenCloningDictionarySettings.cs +++ b/AgileMapper.UnitTests/MapperCloning/WhenCloningDictionarySettings.cs @@ -2,7 +2,7 @@ { using System.Collections.Generic; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/MapperCloning/WhenCloningMemberIgnores.cs b/AgileMapper.UnitTests/MapperCloning/WhenCloningMemberIgnores.cs index 3b58da798..fa37315f1 100644 --- a/AgileMapper.UnitTests/MapperCloning/WhenCloningMemberIgnores.cs +++ b/AgileMapper.UnitTests/MapperCloning/WhenCloningMemberIgnores.cs @@ -2,7 +2,7 @@ { using AgileMapper.Configuration; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/MapperCloning/WhenCloningObjectFactories.cs b/AgileMapper.UnitTests/MapperCloning/WhenCloningObjectFactories.cs index f1d4e4855..808359afc 100644 --- a/AgileMapper.UnitTests/MapperCloning/WhenCloningObjectFactories.cs +++ b/AgileMapper.UnitTests/MapperCloning/WhenCloningObjectFactories.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/MapperCloning/WhenCloningStringFormatting.cs b/AgileMapper.UnitTests/MapperCloning/WhenCloningStringFormatting.cs index 3937caa8c..2100516d2 100644 --- a/AgileMapper.UnitTests/MapperCloning/WhenCloningStringFormatting.cs +++ b/AgileMapper.UnitTests/MapperCloning/WhenCloningStringFormatting.cs @@ -1,7 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.MapperCloning { using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Members/MemberTestsBase.cs b/AgileMapper.UnitTests/Members/MemberTestsBase.cs index 73091a69f..4c2676ff1 100644 --- a/AgileMapper.UnitTests/Members/MemberTestsBase.cs +++ b/AgileMapper.UnitTests/Members/MemberTestsBase.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Linq.Expressions; using AgileMapper.Members; + using AgileMapper.Members.Extensions; using NetStandardPolyfills; public abstract class MemberTestsBase diff --git a/AgileMapper.UnitTests/Members/WhenCreatingTargetMembersFromExpressions.cs b/AgileMapper.UnitTests/Members/WhenCreatingTargetMembersFromExpressions.cs index 652bcbf7f..08c00e19c 100644 --- a/AgileMapper.UnitTests/Members/WhenCreatingTargetMembersFromExpressions.cs +++ b/AgileMapper.UnitTests/Members/WhenCreatingTargetMembersFromExpressions.cs @@ -5,7 +5,9 @@ using System.Linq; using System.Linq.Expressions; using AgileMapper.Members; + using AgileMapper.Members.Extensions; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Members/WhenDeterminingRecursion.cs b/AgileMapper.UnitTests/Members/WhenDeterminingRecursion.cs index db4a234fc..b3d9adb6c 100644 --- a/AgileMapper.UnitTests/Members/WhenDeterminingRecursion.cs +++ b/AgileMapper.UnitTests/Members/WhenDeterminingRecursion.cs @@ -1,7 +1,9 @@ namespace AgileObjects.AgileMapper.UnitTests.Members { using AgileMapper.Members; + using AgileMapper.Members.Extensions; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Members/WhenFindingDataSources.cs b/AgileMapper.UnitTests/Members/WhenFindingDataSources.cs index c2f20b8d1..71cc1f114 100644 --- a/AgileMapper.UnitTests/Members/WhenFindingDataSources.cs +++ b/AgileMapper.UnitTests/Members/WhenFindingDataSources.cs @@ -4,8 +4,8 @@ namespace AgileObjects.AgileMapper.UnitTests.Members using System.Linq.Expressions; using AgileMapper.Members; using Common; + using Common.TestClasses; using ObjectPopulation; - using TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Members/WhenFindingSourceMembers.cs b/AgileMapper.UnitTests/Members/WhenFindingSourceMembers.cs index d315fbf88..246a0ffb7 100644 --- a/AgileMapper.UnitTests/Members/WhenFindingSourceMembers.cs +++ b/AgileMapper.UnitTests/Members/WhenFindingSourceMembers.cs @@ -3,6 +3,7 @@ using System; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Members/WhenFindingTargetMembers.cs b/AgileMapper.UnitTests/Members/WhenFindingTargetMembers.cs index 6b98aac10..00608d1b0 100644 --- a/AgileMapper.UnitTests/Members/WhenFindingTargetMembers.cs +++ b/AgileMapper.UnitTests/Members/WhenFindingTargetMembers.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Members/WhenMatchingSourceToTargetMembers.cs b/AgileMapper.UnitTests/Members/WhenMatchingSourceToTargetMembers.cs index dc346cb9d..668865771 100644 --- a/AgileMapper.UnitTests/Members/WhenMatchingSourceToTargetMembers.cs +++ b/AgileMapper.UnitTests/Members/WhenMatchingSourceToTargetMembers.cs @@ -4,6 +4,7 @@ using System.Linq.Expressions; using AgileMapper.Members; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToBools.cs b/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToBools.cs index 523b26343..a41118f30 100644 --- a/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToBools.cs +++ b/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToBools.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToDateTimeOffsets.cs b/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToDateTimeOffsets.cs index dbb27bc89..0e36a3d49 100644 --- a/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToDateTimeOffsets.cs +++ b/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToDateTimeOffsets.cs @@ -2,7 +2,7 @@ { using System; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToDateTimes.cs b/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToDateTimes.cs index aeee5f028..750b316b4 100644 --- a/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToDateTimes.cs +++ b/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToDateTimes.cs @@ -2,7 +2,7 @@ { using System; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToFlagsEnums.cs b/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToFlagsEnums.cs index b88e391a0..d07c8fe91 100644 --- a/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToFlagsEnums.cs +++ b/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToFlagsEnums.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.SimpleTypeConversion { using Common; + using Common.TestClasses; using TestClasses; using static TestClasses.Status; #if !NET35 diff --git a/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToGuids.cs b/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToGuids.cs index 472dd4616..088070bb4 100644 --- a/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToGuids.cs +++ b/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToGuids.cs @@ -2,6 +2,7 @@ { using System; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToTimeSpans.cs b/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToTimeSpans.cs index 20350f587..537feeb59 100644 --- a/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToTimeSpans.cs +++ b/AgileMapper.UnitTests/SimpleTypeConversion/WhenConvertingToTimeSpans.cs @@ -2,7 +2,7 @@ { using System; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructCreationCallbacks.cs b/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructCreationCallbacks.cs index 6a5e66458..d717ac025 100644 --- a/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructCreationCallbacks.cs +++ b/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructCreationCallbacks.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Structs.Configuration { using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructDataSources.cs b/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructDataSources.cs index eb71e3758..4d4c0f503 100644 --- a/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructDataSources.cs +++ b/AgileMapper.UnitTests/Structs/Configuration/WhenConfiguringStructDataSources.cs @@ -3,6 +3,7 @@ using System; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Structs/Dictionaries/WhenMappingFromDictionariesToStructs.cs b/AgileMapper.UnitTests/Structs/Dictionaries/WhenMappingFromDictionariesToStructs.cs index 5129756be..ea3ee1174 100644 --- a/AgileMapper.UnitTests/Structs/Dictionaries/WhenMappingFromDictionariesToStructs.cs +++ b/AgileMapper.UnitTests/Structs/Dictionaries/WhenMappingFromDictionariesToStructs.cs @@ -4,6 +4,7 @@ using System.Collections.ObjectModel; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Structs/WhenMappingOnToStructMembers.cs b/AgileMapper.UnitTests/Structs/WhenMappingOnToStructMembers.cs index d2766f14c..066195466 100644 --- a/AgileMapper.UnitTests/Structs/WhenMappingOnToStructMembers.cs +++ b/AgileMapper.UnitTests/Structs/WhenMappingOnToStructMembers.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Structs { using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Structs/WhenMappingOnToStructs.cs b/AgileMapper.UnitTests/Structs/WhenMappingOnToStructs.cs index 90461a5af..8b5f231c6 100644 --- a/AgileMapper.UnitTests/Structs/WhenMappingOnToStructs.cs +++ b/AgileMapper.UnitTests/Structs/WhenMappingOnToStructs.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Structs { using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Structs/WhenMappingOverStructMembers.cs b/AgileMapper.UnitTests/Structs/WhenMappingOverStructMembers.cs index b373453c2..6bc5259c3 100644 --- a/AgileMapper.UnitTests/Structs/WhenMappingOverStructMembers.cs +++ b/AgileMapper.UnitTests/Structs/WhenMappingOverStructMembers.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Structs { using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Structs/WhenMappingOverStructs.cs b/AgileMapper.UnitTests/Structs/WhenMappingOverStructs.cs index 4d936d582..245ce6f75 100644 --- a/AgileMapper.UnitTests/Structs/WhenMappingOverStructs.cs +++ b/AgileMapper.UnitTests/Structs/WhenMappingOverStructs.cs @@ -2,6 +2,7 @@ { using System; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Structs/WhenMappingToNewStructMembers.cs b/AgileMapper.UnitTests/Structs/WhenMappingToNewStructMembers.cs index 682a9db13..5595f10d5 100644 --- a/AgileMapper.UnitTests/Structs/WhenMappingToNewStructMembers.cs +++ b/AgileMapper.UnitTests/Structs/WhenMappingToNewStructMembers.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Structs { using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Structs/WhenMappingToNewStructs.cs b/AgileMapper.UnitTests/Structs/WhenMappingToNewStructs.cs index 3ba5524b7..f0cfb93b0 100644 --- a/AgileMapper.UnitTests/Structs/WhenMappingToNewStructs.cs +++ b/AgileMapper.UnitTests/Structs/WhenMappingToNewStructs.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.Structs { using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/Structs/WhenMappingToStructEnumerables.cs b/AgileMapper.UnitTests/Structs/WhenMappingToStructEnumerables.cs index f6d98d8f4..5b0c23564 100644 --- a/AgileMapper.UnitTests/Structs/WhenMappingToStructEnumerables.cs +++ b/AgileMapper.UnitTests/Structs/WhenMappingToStructEnumerables.cs @@ -4,6 +4,7 @@ using System.Collections.ObjectModel; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; using static System.Decimal; #if !NET35 diff --git a/AgileMapper.UnitTests/Structs/WhenMappingToUnmappableStructMembers.cs b/AgileMapper.UnitTests/Structs/WhenMappingToUnmappableStructMembers.cs index cf20414f5..26344ea4e 100644 --- a/AgileMapper.UnitTests/Structs/WhenMappingToUnmappableStructMembers.cs +++ b/AgileMapper.UnitTests/Structs/WhenMappingToUnmappableStructMembers.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/TestClasses/MegaProduct.cs b/AgileMapper.UnitTests/TestClasses/MegaProduct.cs deleted file mode 100644 index 5061258e4..000000000 --- a/AgileMapper.UnitTests/TestClasses/MegaProduct.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace AgileObjects.AgileMapper.UnitTests.TestClasses -{ - internal class MegaProduct : Product - { - public decimal HowMega { get; set; } - } -} \ No newline at end of file diff --git a/AgileMapper.UnitTests/TestClasses/OrderItemDto.cs b/AgileMapper.UnitTests/TestClasses/OrderItemDto.cs index c73b9af1a..ec2e154ff 100644 --- a/AgileMapper.UnitTests/TestClasses/OrderItemDto.cs +++ b/AgileMapper.UnitTests/TestClasses/OrderItemDto.cs @@ -1,5 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests.TestClasses { + using Common.TestClasses; + internal class OrderItemDto : DtoBase { public int OrderId { get; set; } diff --git a/AgileMapper.UnitTests/TestClasses/ProductDtoMega.cs b/AgileMapper.UnitTests/TestClasses/ProductDtoMega.cs deleted file mode 100644 index 947b7bc7c..000000000 --- a/AgileMapper.UnitTests/TestClasses/ProductDtoMega.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace AgileObjects.AgileMapper.UnitTests.TestClasses -{ - internal class ProductDtoMega : ProductDto - { - public string HowMega { get; set; } - } -} \ No newline at end of file diff --git a/AgileMapper.UnitTests/WhenAccessingDisposedMappers.cs b/AgileMapper.UnitTests/WhenAccessingDisposedMappers.cs index a8d30ad60..ddd182ce1 100644 --- a/AgileMapper.UnitTests/WhenAccessingDisposedMappers.cs +++ b/AgileMapper.UnitTests/WhenAccessingDisposedMappers.cs @@ -3,6 +3,7 @@ using System; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/WhenAnalysingCollections.cs b/AgileMapper.UnitTests/WhenAnalysingCollections.cs index 1aef249ee..fcb7db784 100644 --- a/AgileMapper.UnitTests/WhenAnalysingCollections.cs +++ b/AgileMapper.UnitTests/WhenAnalysingCollections.cs @@ -4,6 +4,7 @@ using System.Linq; using AgileMapper.Extensions; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/WhenMappingCircularReferences.cs b/AgileMapper.UnitTests/WhenMappingCircularReferences.cs index 6258b92b1..e64acebed 100644 --- a/AgileMapper.UnitTests/WhenMappingCircularReferences.cs +++ b/AgileMapper.UnitTests/WhenMappingCircularReferences.cs @@ -7,6 +7,7 @@ using AgileMapper.Extensions; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/WhenMappingDerivedTypes.cs b/AgileMapper.UnitTests/WhenMappingDerivedTypes.cs index 0f66bde67..f27dd9ab8 100644 --- a/AgileMapper.UnitTests/WhenMappingDerivedTypes.cs +++ b/AgileMapper.UnitTests/WhenMappingDerivedTypes.cs @@ -6,6 +6,7 @@ using System.Collections.ObjectModel; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; @@ -17,7 +18,7 @@ public class WhenMappingDerivedTypes { [Fact] - public void ShouldMapARootComplexTypeFromItsAssignedType() + public void ShouldMapARootComplexTypeFromItsRuntimeType() { object source = new Product { Price = 100.00 }; var result = Mapper.Map(source).ToANew(); @@ -26,7 +27,7 @@ public void ShouldMapARootComplexTypeFromItsAssignedType() } [Fact] - public void ShouldMapARootComplexTypeEnumerableFromItsAssignedType() + public void ShouldMapARootComplexTypeEnumerableFromItsRuntimeType() { object source = new[] { new Product { Price = 10.01 } }; var result = Mapper.Map(source).ToANew>(); @@ -35,7 +36,7 @@ public void ShouldMapARootComplexTypeEnumerableFromItsAssignedType() } [Fact] - public void ShouldMapARootComplexTypeEnumerableElementFromItsAssignedType() + public void ShouldMapARootComplexTypeEnumerableElementFromItsRuntimeType() { var source = new object[] { new Product { Price = 9.99 } }; var result = Mapper.Map(source).ToANew>(); @@ -44,7 +45,7 @@ public void ShouldMapARootComplexTypeEnumerableElementFromItsAssignedType() } [Fact] - public void ShouldMapAComplexTypeMemberFromItsAssignedType() + public void ShouldMapAComplexTypeMemberFromItsRuntimeType() { var source = new PublicProperty { @@ -59,7 +60,7 @@ public void ShouldMapAComplexTypeMemberFromItsAssignedType() } [Fact] - public void ShouldMapAComplexTypeMemberInACollectionFromItsAssignedType() + public void ShouldMapAComplexTypeMemberInACollectionFromItsRuntimeType() { var sourceObjectId = Guid.NewGuid(); @@ -112,14 +113,13 @@ public void ShouldMapDerivedTypesFromNestedMembers() .Map() .To(); - var personSource = new PublicField + var productSource = new PublicField { Value = new MegaProduct { HowMega = 1.10m } }; - var result = mapper.Map(personSource).ToANew>(); + var result = mapper.Map(productSource).ToANew>(); - result.Value.ShouldBeOfType(); - ((ProductDtoMega)result.Value).HowMega.ShouldBe("1.10"); + result.Value.ShouldBeOfType().HowMega.ShouldBe("1.10"); } } @@ -143,8 +143,7 @@ public void ShouldConditionallyMapDerivedTypesFromNestedMembers() }; var result = mapper.Map(mysteryCustomerSource).ToANew>(); - result.Value.ShouldBeOfType(); - ((MysteryCustomerViewModel)result.Value).Discount.ShouldBe(0.5); + result.Value.ShouldBeOfType().Discount.ShouldBe(0.5); var customerSource = new PublicField { diff --git a/AgileMapper.UnitTests/WhenMappingOnToComplexTypeMembers.cs b/AgileMapper.UnitTests/WhenMappingOnToComplexTypeMembers.cs index a1a7ba351..8627b9f83 100644 --- a/AgileMapper.UnitTests/WhenMappingOnToComplexTypeMembers.cs +++ b/AgileMapper.UnitTests/WhenMappingOnToComplexTypeMembers.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests { using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/WhenMappingOnToComplexTypes.cs b/AgileMapper.UnitTests/WhenMappingOnToComplexTypes.cs index 336fa78e0..464d90556 100644 --- a/AgileMapper.UnitTests/WhenMappingOnToComplexTypes.cs +++ b/AgileMapper.UnitTests/WhenMappingOnToComplexTypes.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests { using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/WhenMappingOnToEnumerableMembers.cs b/AgileMapper.UnitTests/WhenMappingOnToEnumerableMembers.cs index ba8825696..a573dce66 100644 --- a/AgileMapper.UnitTests/WhenMappingOnToEnumerableMembers.cs +++ b/AgileMapper.UnitTests/WhenMappingOnToEnumerableMembers.cs @@ -5,6 +5,7 @@ using System.Collections.ObjectModel; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/WhenMappingOnToEnumerables.cs b/AgileMapper.UnitTests/WhenMappingOnToEnumerables.cs index f84b33ac1..6c141b9f2 100644 --- a/AgileMapper.UnitTests/WhenMappingOnToEnumerables.cs +++ b/AgileMapper.UnitTests/WhenMappingOnToEnumerables.cs @@ -5,6 +5,7 @@ using System.Collections.ObjectModel; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; @@ -22,8 +23,7 @@ public void ShouldMergeARootSimpleTypeArray() var target = new[] { 1, 2, 3 }; var result = Mapper.Map(source).OnTo(target); - result.ShouldNotBeNull(); - result.ShouldBe(1, 2, 3, 4, 5, 6); + result.ShouldNotBeNull().ShouldBe(1, 2, 3, 4, 5, 6); } [Fact] @@ -33,8 +33,7 @@ public void ShouldMergeARootSimpleTypeReadOnlyCollection() var target = new ReadOnlyCollection(new[] { "1", "2" }); var result = Mapper.Map(source).OnTo(target); - result.ShouldNotBeNull(); - result.ShouldBe("1", "2", "3", "4"); + result.ShouldNotBeNull().ShouldBe("1", "2", "3", "4"); } [Fact] @@ -44,8 +43,7 @@ public void ShouldMergeARootSimpleTypeList() var target = new List { "Oh", "Heck", "Yes" }; var result = Mapper.Map(source).OnTo(target); - result.ShouldBeSameAs(target); - result.ShouldBe("Oh", "Heck", "Yes", "I", "Will"); + result.ShouldBeSameAs(target).ShouldBe("Oh", "Heck", "Yes", "I", "Will"); } [Fact] @@ -55,8 +53,7 @@ public void ShouldMergeARootSimpleTypeCollection() ICollection target = new List { "Four", "Three" }; var result = Mapper.Map(source).OnTo(target); - result.ShouldBeSameAs(target); - result.ShouldBe("Four", "Three", "Two", "One"); + result.ShouldBeSameAs(target).ShouldBe("Four", "Three", "Two", "One"); } [Fact] @@ -66,8 +63,7 @@ public void ShouldExcludeExistingTargetElementsInMerge() var target = new List { "One", "Two" }; var result = Mapper.Map(source).OnTo(target); - result.ShouldBeSameAs(target); - result.ShouldBe("One", "Two", "Three"); + result.ShouldBeSameAs(target).ShouldBe("One", "Two", "Three"); } [Fact] @@ -77,12 +73,11 @@ public void ShouldNotExcludeAllExistingTargetElementsInMerge() var target = new List { "One", "Two" }; var result = Mapper.Map(source).OnTo(target); - result.ShouldBeSameAs(target); - result.ShouldBe("One", "Two", "Two", "Three"); + result.ShouldBeSameAs(target).ShouldBe("One", "Two", "Two", "Three"); } [Fact] - public void ShouldMergeARootComplexTypeList() + public void ShouldMergeAComplexTypeList() { var source = new[] { @@ -96,12 +91,11 @@ public void ShouldMergeARootComplexTypeList() var result = Mapper.Map(source).OnTo(target); - result.ShouldBeSameAs(target); - result.ShouldBe(p => p.Name, "Kate", "Pete"); + result.ShouldBeSameAs(target).ShouldBe(p => p.Name, "Kate", "Pete"); } [Fact] - public void ShouldMergeARootSimpleTypeHashSet() + public void ShouldMergeASimpleTypeHashSet() { var source = new[] { 1.0m, 2.0m, 3.0m }; var target = new HashSet { 2.0, 3.0, 4.0 }; @@ -112,7 +106,7 @@ public void ShouldMergeARootSimpleTypeHashSet() } [Fact] - public void ShouldMergeARootComplexTypeReadOnlyCollection() + public void ShouldMergeAComplexTypeReadOnlyCollection() { var source = new[] { @@ -144,8 +138,7 @@ public void ShouldUpdateAnExistingObject() var result = Mapper.Map(source).OnTo(target); - result.ShouldBeSameAs(target); - result.First().Name.ShouldBe(source.First().Name); + result.ShouldBeSameAs(target).ShouldHaveSingleItem().Name.ShouldBe("Pete"); } [Fact] @@ -166,8 +159,7 @@ public void ShouldUpdateAnExistingObjectByConvertedId() var originalObject = target.First(); var result = Mapper.Map(source).OnTo(target); - result.ShouldBeSameAs(target); - result.ShouldContain(originalObject); + result.ShouldBeSameAs(target).ShouldContain(originalObject); result.First().Name.ShouldBe(source.First().Name); } diff --git a/AgileMapper.UnitTests/WhenMappingOverComplexTypeMembers.cs b/AgileMapper.UnitTests/WhenMappingOverComplexTypeMembers.cs index aa67cf228..75c4eca0c 100644 --- a/AgileMapper.UnitTests/WhenMappingOverComplexTypeMembers.cs +++ b/AgileMapper.UnitTests/WhenMappingOverComplexTypeMembers.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.UnitTests { using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/WhenMappingOverComplexTypes.cs b/AgileMapper.UnitTests/WhenMappingOverComplexTypes.cs index 49f78de65..84e430701 100644 --- a/AgileMapper.UnitTests/WhenMappingOverComplexTypes.cs +++ b/AgileMapper.UnitTests/WhenMappingOverComplexTypes.cs @@ -2,6 +2,7 @@ { using System; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; @@ -42,7 +43,19 @@ public void ShouldOverwriteAnExistingSimpleTypePropertyValue() Mapper.Map(source).Over(target); - target.Value.ShouldBe(source.Value); + target.Value.ShouldBe(123); + } + + [Fact] + public void ShouldOverwriteExistingSimpleTypePropertyValues() + { + var source = new Address { Line1 = "Source 1", Line2 = "Source 2" }; + var target = new Address { Line1 = "Target 1", Line2 = "Target 2" }; + + Mapper.Map(source).Over(target); + + target.Line1.ShouldBe("Source 1"); + target.Line2.ShouldBe("Source 2"); } [Fact] diff --git a/AgileMapper.UnitTests/WhenMappingOverEnumerableMembers.cs b/AgileMapper.UnitTests/WhenMappingOverEnumerableMembers.cs index dbf896642..9ee98b8f6 100644 --- a/AgileMapper.UnitTests/WhenMappingOverEnumerableMembers.cs +++ b/AgileMapper.UnitTests/WhenMappingOverEnumerableMembers.cs @@ -5,6 +5,7 @@ using System.Collections.ObjectModel; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; using static System.Decimal; #if !NET35 diff --git a/AgileMapper.UnitTests/WhenMappingOverEnumerables.cs b/AgileMapper.UnitTests/WhenMappingOverEnumerables.cs index d95c31dfd..9b22e0876 100644 --- a/AgileMapper.UnitTests/WhenMappingOverEnumerables.cs +++ b/AgileMapper.UnitTests/WhenMappingOverEnumerables.cs @@ -5,6 +5,7 @@ using System.Collections.ObjectModel; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; @@ -16,29 +17,28 @@ public class WhenMappingOverEnumerables { [Fact] - public void ShouldOverwriteARootSimpleTypeArray() + public void ShouldOverwriteASimpleTypeArray() { var source = new[] { '5', '4', '3', '2' }; var target = new[] { 9, 8, 7, 1 }; var result = Mapper.Map(source).Over(target); - result.ShouldNotBeNull(); + result.ShouldNotBeNull().ShouldNotBeSameAs(target); result.ShouldBe(5, 4, 3, 2); } [Fact] - public void ShouldOverwriteARootSimpleTypeReadOnlyCollection() + public void ShouldOverwriteASimpleTypeReadOnlyCollection() { var source = new[] { '2', '3' }; var target = new ReadOnlyCollection(new List { '5', '4' }); var result = Mapper.Map(source).Over(target); - result.ShouldNotBeNull(); - result.ShouldBe('2', '3'); + result.ShouldNotBeNull().ShouldBe('2', '3'); } [Fact] - public void ShouldOverwriteARootSimpleTypeList() + public void ShouldOverwriteASimpleTypeList() { var source = new List { "I", "Will" }; var target = new List { "You", "Might" }; @@ -49,7 +49,7 @@ public void ShouldOverwriteARootSimpleTypeList() } [Fact] - public void ShouldOverwriteARootSimpleTypeEnumerable() + public void ShouldOverwriteASimpleTypeEnumerable() { var source = new List { 234, 567 }; IEnumerable target = new List { 654, 321 }; @@ -60,7 +60,7 @@ public void ShouldOverwriteARootSimpleTypeEnumerable() } [Fact] - public void ShouldOverwriteARootComplexTypeList() + public void ShouldOverwriteAComplexTypeList() { var source = new[] { @@ -81,7 +81,7 @@ public void ShouldOverwriteARootComplexTypeList() } [Fact] - public void ShouldOverwriteARootComplexTypeCollectionElementByRuntimeType() + public void ShouldOverwriteAComplexTypeCollectionElementByRuntimeType() { var id = Guid.NewGuid(); diff --git a/AgileMapper.UnitTests/WhenMappingToConstructors.cs b/AgileMapper.UnitTests/WhenMappingToConstructors.cs index 53bae55bc..4ba9fe7d5 100644 --- a/AgileMapper.UnitTests/WhenMappingToConstructors.cs +++ b/AgileMapper.UnitTests/WhenMappingToConstructors.cs @@ -9,6 +9,7 @@ using System.Reflection; #endif using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/WhenMappingToMetaMembers.cs b/AgileMapper.UnitTests/WhenMappingToMetaMembers.cs index 8ef332a8a..c7b0067be 100644 --- a/AgileMapper.UnitTests/WhenMappingToMetaMembers.cs +++ b/AgileMapper.UnitTests/WhenMappingToMetaMembers.cs @@ -6,7 +6,7 @@ using System.Linq; using AgileMapper.Extensions; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/WhenMappingToNewComplexTypeMembers.cs b/AgileMapper.UnitTests/WhenMappingToNewComplexTypeMembers.cs index 16345d7c5..8a1a1082b 100644 --- a/AgileMapper.UnitTests/WhenMappingToNewComplexTypeMembers.cs +++ b/AgileMapper.UnitTests/WhenMappingToNewComplexTypeMembers.cs @@ -4,6 +4,7 @@ using AgileMapper.Extensions; using AgileMapper.Extensions.Internal; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/WhenMappingToNewComplexTypes.cs b/AgileMapper.UnitTests/WhenMappingToNewComplexTypes.cs index d766809df..5041029f7 100644 --- a/AgileMapper.UnitTests/WhenMappingToNewComplexTypes.cs +++ b/AgileMapper.UnitTests/WhenMappingToNewComplexTypes.cs @@ -3,6 +3,7 @@ using System; using AgileMapper.Extensions; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/WhenMappingToNewEnumerableMembers.cs b/AgileMapper.UnitTests/WhenMappingToNewEnumerableMembers.cs index 8400194bf..de947f006 100644 --- a/AgileMapper.UnitTests/WhenMappingToNewEnumerableMembers.cs +++ b/AgileMapper.UnitTests/WhenMappingToNewEnumerableMembers.cs @@ -7,6 +7,7 @@ #endif using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/WhenMappingToNewEnumerables.cs b/AgileMapper.UnitTests/WhenMappingToNewEnumerables.cs index 0e1a0450e..d4fa546be 100644 --- a/AgileMapper.UnitTests/WhenMappingToNewEnumerables.cs +++ b/AgileMapper.UnitTests/WhenMappingToNewEnumerables.cs @@ -5,6 +5,7 @@ using System.Collections.ObjectModel; using System.Linq; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; @@ -42,8 +43,7 @@ public void ShouldCreateAConvertedSimpleTypeCollection() var source = new List { "1", "2", "3" }; var result = Mapper.Map(source).ToANew>(); - result.ShouldNotBeNull(); - result.ShouldBe(1, 2, 3); + result.ShouldNotBeNull().ShouldBe(1, 2, 3); } [Fact] @@ -102,8 +102,7 @@ public void ShouldCreateAReadOnlyCollection() var source = new[] { 1, 2, 3 }; var result = Mapper.Map(source).ToANew>(); - result.ShouldNotBeNull(); - result.ShouldBe(1, 2, 3); + result.ShouldNotBeNull().ShouldBe(1, 2, 3); } [Fact] @@ -112,8 +111,7 @@ public void ShouldMapFromAReadOnlyCollection() var source = new ReadOnlyCollection(new[] { 1, 2, 3L }); var result = Mapper.Map(source).ToANew(); - result.ShouldNotBeNull(); - result.ShouldBe(1, 2, 3); + result.ShouldNotBeNull().ShouldBe(1, 2, 3); } #if !NET35 @@ -123,8 +121,7 @@ public void ShouldCreateAnIReadOnlyCollection() var source = new[] { 1, 2, 3 }; var result = Mapper.Map(source).ToANew>(); - result.ShouldNotBeNull(); - result.ShouldBe((short)1, (short)2, (short)3); + result.ShouldNotBeNull().ShouldBe(1, 2, 3); } #endif [Fact] @@ -137,8 +134,7 @@ public void ShouldMapFromAHashset() var source = new HashSet { yesterday, today, tomorrow }; var result = Mapper.Map(source).ToANew(); - result.ShouldNotBeNull(); - result.ShouldBe(yesterday, today, tomorrow); + result.ShouldNotBeNull().ShouldBe(yesterday, today, tomorrow); } #if !NET35 @@ -148,8 +144,7 @@ public void ShouldMapToAnISet() var source = new[] { "1", "2", "3" }; var result = Mapper.Map(source).ToANew>(); - result.ShouldNotBeNull(); - result.ShouldBe(1L, 2L, 3L); + result.ShouldNotBeNull().ShouldBe(1L, 2L, 3L); } #endif [Fact] diff --git a/AgileMapper.UnitTests/WhenUnflatteningFromQueryStrings.cs b/AgileMapper.UnitTests/WhenUnflatteningFromQueryStrings.cs index 88b8d3866..dd4dd9364 100644 --- a/AgileMapper.UnitTests/WhenUnflatteningFromQueryStrings.cs +++ b/AgileMapper.UnitTests/WhenUnflatteningFromQueryStrings.cs @@ -4,7 +4,7 @@ using System.Collections.ObjectModel; using AgileMapper.Extensions; using Common; - using TestClasses; + using Common.TestClasses; #if !NET35 using Xunit; #else diff --git a/AgileMapper.UnitTests/WhenUsingFactoryMethods.cs b/AgileMapper.UnitTests/WhenUsingFactoryMethods.cs index f6c9b2d3d..3e9fc6df1 100644 --- a/AgileMapper.UnitTests/WhenUsingFactoryMethods.cs +++ b/AgileMapper.UnitTests/WhenUsingFactoryMethods.cs @@ -2,6 +2,7 @@ { using AgileMapper.Configuration; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; diff --git a/AgileMapper.UnitTests/WhenUsingPartialTrust.cs b/AgileMapper.UnitTests/WhenUsingPartialTrust.cs index 9648862c3..0b08fbd1d 100644 --- a/AgileMapper.UnitTests/WhenUsingPartialTrust.cs +++ b/AgileMapper.UnitTests/WhenUsingPartialTrust.cs @@ -231,9 +231,9 @@ public void TestMappingPlan() plan); Assert.Contains("// Rule Set: Overwrite", plan); - Assert.Contains("ptfooaToPtfccData.Map(", plan); + Assert.Contains("ooaptfToCcieptfData.Map(", plan); Assert.Contains("\"Value1\"", plan); - Assert.Contains("customers.Add(oaToCsData.Map(objectArray[i]", RemoveWhiteSpace(plan)); + Assert.Contains("customerICollection.Add(oaToCieData.Map(objectArray[i]", RemoveWhiteSpace(plan)); } #region Helper Members diff --git a/AgileMapper.UnitTests/WhenViewingMappingPlans.cs b/AgileMapper.UnitTests/WhenViewingMappingPlans.cs index 1de12cc7d..f3b7991b5 100644 --- a/AgileMapper.UnitTests/WhenViewingMappingPlans.cs +++ b/AgileMapper.UnitTests/WhenViewingMappingPlans.cs @@ -10,6 +10,7 @@ #endif using System.Text.RegularExpressions; using Common; + using Common.TestClasses; using TestClasses; #if !NET35 using Xunit; @@ -27,7 +28,7 @@ public void ShouldShowASimpleTypeMemberMapping() .GetPlanFor>() .ToANew>(); - plan.ShouldContain("publicProperty_String.Value = pfsToPpsData.Source.Value;"); + plan.ShouldContain("stringPublicProperty.Value = spfToSppData.Source.Value;"); } [Fact] @@ -60,8 +61,8 @@ public void ShouldSupportAnonymousSourceTypesFromTheStaticApi() .ToANew(); plan.ShouldContain("Map AnonymousType -> MysteryCustomer"); - plan.ShouldContain("mysteryCustomer.Name = fatsiToMcData.Source.Name;"); - plan.ShouldContain("mysteryCustomer.Discount = fatsiToMcData.Source.Discount;"); + plan.ShouldContain("mysteryCustomer.Name = siatToMcData.Source.Name;"); + plan.ShouldContain("mysteryCustomer.Discount = siatToMcData.Source.Discount;"); plan.ShouldContain("// No data sources for Report"); } @@ -75,8 +76,8 @@ public void ShouldSupportAnonymousSourceTypesFromTheInstanceApi() .OnTo(); plan.ShouldContain("Map AnonymousType -> Customer"); - plan.ShouldContain(".Target.Name = fatssToCData.Source.Name"); - plan.ShouldContain("address.Line1 = fatssToCData.Source.AddressLine1"); + plan.ShouldContain(".Target.Name = ssatToCData.Source.Name"); + plan.ShouldContain("address.Line1 = ssatToCData.Source.AddressLine1"); } } @@ -87,7 +88,7 @@ public void ShouldSupportStructsFromTheStaticApi() .GetPlanFor>() .Over>(); - plan.ShouldContain("publicTwoFieldsStruct_String_String.Value1 = ptfsiiToPtfsssData.Source.Value1.ToString();"); + plan.ShouldContain("stringStringPublicTwoFieldsStruct.Value1 = iiptfsToSsptfsData.Source.Value1.ToString();"); } [Fact] @@ -97,7 +98,7 @@ public void ShouldSupportStructMergePlansFromTheStaticApi() .GetPlanFor>() .OnTo>(); - plan.ShouldContain("publicTwoFieldsStruct_String_String.Value1 = ptfsiiToPtfsssData.Source.Value1.ToString();"); + plan.ShouldContain("stringStringPublicTwoFieldsStruct.Value1 = iiptfsToSsptfsData.Source.Value1.ToString();"); } [Fact] @@ -110,8 +111,8 @@ public void ShouldSupportStructsFromTheInstanceApi() .ToANew>(); plan.ShouldContain("Map PublicPropertyStruct -> PublicCtorStruct"); - plan.ShouldContain("new PublicCtorStruct(ppssToPcssData.Source.Value)"); - plan.ShouldContain("return publicCtorStruct_String"); + plan.ShouldContain("new PublicCtorStruct(sppsToSpcsData.Source.Value)"); + plan.ShouldContain("return stringPublicCtorStruct"); } } @@ -134,10 +135,10 @@ public void ShouldShowASimpleTypeEnumerableMemberMapping() .ToANew>>(); plan.ShouldContain("sourceIntArray = "); - plan.ShouldContain("ICollection targetInts = "); - plan.ShouldContain(" = publicField_Ints.Value as ICollection) != null"); - plan.ShouldContain("new List(publicField_Ints.Value)"); - plan.ShouldContain("targetInts.Add(sourceIntArray[i])"); + plan.ShouldContain("ICollection targetIntICollection = "); + plan.ShouldContain(" = intIEnumerablePublicField.Value as ICollection) != null"); + plan.ShouldContain("new List(intIEnumerablePublicField.Value)"); + plan.ShouldContain("targetIntICollection.Add(sourceIntArray[i])"); } [Fact] @@ -147,7 +148,7 @@ public void ShouldShowASimpleTypeMemberConversion() .GetPlanFor>() .ToANew>(); - plan.ShouldContain("ppgToPfsData.Source.Value.ToString("); + plan.ShouldContain("gppToSpfData.Source.Value.ToString("); } [Fact] @@ -157,8 +158,8 @@ public void ShouldShowARootComplexTypeEnumerableMapping() .GetPlanFor>() .OnTo>(); - plan.ShouldContain("collectionData.Intersection.ForEach((person, personViewModel, i) =>"); - plan.ShouldContain("persons = collectionData.NewSourceItems"); + plan.ShouldContain("collectionData.Intersection.ForEach((existingPerson, existingPersonViewModel, idx) =>"); + plan.ShouldContain("personIEnumerable = collectionData.NewSourceItems"); } [Fact] @@ -168,13 +169,13 @@ public void ShouldShowAComplexTypeEnumerableMemberMapping() .GetPlanFor>() .Over>(); - plan.ShouldContain("personViewModels = collectionData.NewSourceItems"); - plan.ShouldContain("collectionData.Intersection.ForEach((personViewModel, person, i) =>"); - plan.ShouldContain("collectionData.AbsentTargetItems.ForEach(persons.Remove)"); + plan.ShouldContain("personViewModelIEnumerable = collectionData.NewSourceItems"); + plan.ShouldContain("collectionData.Intersection.ForEach((existingPersonViewModel, existingPerson, idx) =>"); + plan.ShouldContain("collectionData.AbsentTargetItems.ForEach(p => personICollection.Remove(p)"); plan.ShouldContain("IList -> IEnumerable"); - plan.ShouldNotContain("PersonViewModel -> Person"); // <- because the mapping is inlined - plan.ShouldNotContain("PersonViewModel -> Address"); // <- because the mapping is inlined + plan.ShouldNotContain("PersonViewModel -> Person"); + plan.ShouldNotContain("PersonViewModel -> Address"); } [Fact] @@ -207,7 +208,7 @@ public void ShouldShowMapChildCalls() .ToANew>(); plan.ShouldContain("// Map PublicProperty -> PublicSetMethod"); - plan.ShouldContain("ppoToPsmcData.Map("); + plan.ShouldContain("oppToCpsmData.Map("); plan.ShouldContain("\"SetValue\""); } @@ -220,7 +221,7 @@ public void ShouldShowNestedMapChildCalls() plan.ShouldContain("// Map PublicProperty> -> PublicSetMethod>"); plan.ShouldNotContain("// Map PublicField -> PublicProperty"); - plan.ShouldContain("pfoToPpoData.Map("); + plan.ShouldContain("opfToOppData.Map("); plan.ShouldContain("\"Value\""); } @@ -232,7 +233,7 @@ public void ShouldShowMapElementCalls() .ToANew>>(); plan.ShouldContain("// Map PublicProperty -> PublicSetMethod>"); - RemoveWhiteSpace(plan).ShouldContain("products.Add(oaToPsData.Map(objectArray[i]"); + RemoveWhiteSpace(plan).ShouldContain("productList.Add(oaToPicData.Map(objectArray[i]"); } // See https://github.com/agileobjects/AgileMapper/issues/24 @@ -410,7 +411,7 @@ public void ShouldShowUnmappableStructComplexTypeMemberDetails() .GetPlanFor>() .ToANew>(); - plan.ShouldContain("int.TryParse(ptfpsToPtfspiData.Source.Value2"); + plan.ShouldContain("int.TryParse(psptfToPiptfsData.Source.Value2"); plan.ShouldContain("Person member on a struct"); } } @@ -434,7 +435,7 @@ public void ShouldShowAllCachedMappingPlans() mapper.GetPlanFor().ToANew(); mapper.GetPlansFor(new MegaProduct()).To(); - var plan = mapper.GetPlansInCache(); + string plan = mapper.GetPlansInCache(); plan.ShouldContain("PublicField -> PublicProperty"); plan.ShouldContain("Customer -> CustomerViewModel"); @@ -456,9 +457,9 @@ public void ShouldShowAllCachedMappingPlanExpressions() mapper.GetPlanFor().ToANew(); mapper.GetPlansFor(new MegaProduct()).To(); - var plan = mapper.GetPlanExpressionsInCache(); + var expressions = mapper.GetPlanExpressionsInCache(); - plan.ShouldNotBeNull(); + expressions.ShouldNotBeNull().Any().ShouldBeTrue(); } } diff --git a/AgileMapper.sln b/AgileMapper.sln index a4a4939f3..1a132b130 100644 --- a/AgileMapper.sln +++ b/AgileMapper.sln @@ -55,6 +55,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AgileMapper.UnitTests.NetCo EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AgileMapper.UnitTests.NetCore2", "AgileMapper.UnitTests.NetCore2\AgileMapper.UnitTests.NetCore2.csproj", "{72287439-1634-4164-ABAC-E4A462235C5D}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Buildable", "Buildable", "{C0C3194B-D7C8-470F-8B7D-47BA75E0EDAE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AgileMapper.Buildable", "AgileMapper.Buildable\AgileMapper.Buildable.csproj", "{F55FFD5B-EF1F-4937-B2D2-B3324F9962D6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AgileMapper.Buildable.UnitTests", "AgileMapper.Buildable.UnitTests\AgileMapper.Buildable.UnitTests.csproj", "{B305D680-C129-4785-B02B-10F293E19A75}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AgileMapper.Buildable.UnitTests.NetCore3", "AgileMapper.Buildable.UnitTests.NetCore3\AgileMapper.Buildable.UnitTests.NetCore3.csproj", "{C7726D80-F144-430B-8C07-E500BE75217F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AgileMapper.Buildable.UnitTests.NetStandard2.Mappers", "AgileMapper.Buildable.UnitTests.NetStandard2.Mappers\AgileMapper.Buildable.UnitTests.NetStandard2.Mappers.csproj", "{2FD6FF7D-658B-495B-911B-6FC6D227D0B5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AgileMapper.Buildable.UnitTests.NetStandard2.Generator", "AgileMapper.Buildable.UnitTests.NetStandard2.Generator\AgileMapper.Buildable.UnitTests.NetStandard2.Generator.csproj", "{8D62F519-4FA2-48A5-9E1E-B6E0A3A90D4E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -137,6 +149,26 @@ Global {72287439-1634-4164-ABAC-E4A462235C5D}.Debug|Any CPU.Build.0 = Debug|Any CPU {72287439-1634-4164-ABAC-E4A462235C5D}.Release|Any CPU.ActiveCfg = Release|Any CPU {72287439-1634-4164-ABAC-E4A462235C5D}.Release|Any CPU.Build.0 = Release|Any CPU + {F55FFD5B-EF1F-4937-B2D2-B3324F9962D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F55FFD5B-EF1F-4937-B2D2-B3324F9962D6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F55FFD5B-EF1F-4937-B2D2-B3324F9962D6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F55FFD5B-EF1F-4937-B2D2-B3324F9962D6}.Release|Any CPU.Build.0 = Release|Any CPU + {B305D680-C129-4785-B02B-10F293E19A75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B305D680-C129-4785-B02B-10F293E19A75}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B305D680-C129-4785-B02B-10F293E19A75}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B305D680-C129-4785-B02B-10F293E19A75}.Release|Any CPU.Build.0 = Release|Any CPU + {C7726D80-F144-430B-8C07-E500BE75217F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7726D80-F144-430B-8C07-E500BE75217F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7726D80-F144-430B-8C07-E500BE75217F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7726D80-F144-430B-8C07-E500BE75217F}.Release|Any CPU.Build.0 = Release|Any CPU + {2FD6FF7D-658B-495B-911B-6FC6D227D0B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2FD6FF7D-658B-495B-911B-6FC6D227D0B5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2FD6FF7D-658B-495B-911B-6FC6D227D0B5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2FD6FF7D-658B-495B-911B-6FC6D227D0B5}.Release|Any CPU.Build.0 = Release|Any CPU + {8D62F519-4FA2-48A5-9E1E-B6E0A3A90D4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D62F519-4FA2-48A5-9E1E-B6E0A3A90D4E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D62F519-4FA2-48A5-9E1E-B6E0A3A90D4E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D62F519-4FA2-48A5-9E1E-B6E0A3A90D4E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -162,6 +194,11 @@ Global {5085AA3F-A5B7-40E2-9309-7E0B81FBE113} = {88D48136-E176-4AF7-ACA4-A2954F3BD55B} {F9307FDB-0F73-40AB-B7AC-AE79CFA5521C} = {88D48136-E176-4AF7-ACA4-A2954F3BD55B} {72287439-1634-4164-ABAC-E4A462235C5D} = {88D48136-E176-4AF7-ACA4-A2954F3BD55B} + {F55FFD5B-EF1F-4937-B2D2-B3324F9962D6} = {C0C3194B-D7C8-470F-8B7D-47BA75E0EDAE} + {B305D680-C129-4785-B02B-10F293E19A75} = {C0C3194B-D7C8-470F-8B7D-47BA75E0EDAE} + {C7726D80-F144-430B-8C07-E500BE75217F} = {C0C3194B-D7C8-470F-8B7D-47BA75E0EDAE} + {2FD6FF7D-658B-495B-911B-6FC6D227D0B5} = {C0C3194B-D7C8-470F-8B7D-47BA75E0EDAE} + {8D62F519-4FA2-48A5-9E1E-B6E0A3A90D4E} = {C0C3194B-D7C8-470F-8B7D-47BA75E0EDAE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C39E9BDB-0077-445C-8F09-801CAE1AF8AB} diff --git a/AgileMapper.sln.DotSettings b/AgileMapper.sln.DotSettings index ec676422d..e1b1995be 100644 --- a/AgileMapper.sln.DotSettings +++ b/AgileMapper.sln.DotSettings @@ -44,5 +44,7 @@ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + True + True <data><IncludeFilters /><ExcludeFilters /></data> <data><AttributeFilter ClassMask="AgileObjects.AgileMapper.ExcludeFromCodeCoverageAttribute" IsEnabled="True" /></data> \ No newline at end of file diff --git a/AgileMapper/AgileMapper.csproj b/AgileMapper/AgileMapper.csproj index 8a117906b..d3023f5bf 100644 --- a/AgileMapper/AgileMapper.csproj +++ b/AgileMapper/AgileMapper.csproj @@ -2,7 +2,6 @@ net35;net40;netstandard1.0;netstandard1.3;netstandard2.0 - latest AgileObjects.AgileMapper AgileObjects.AgileMapper AgileObjects.AgileMapper @@ -14,18 +13,20 @@ AgileObjects.AgileMapper AgileMapper A zero-configuration, highly-configurable, unopinionated object mapper with viewable execution plans. Flattens, unflattens, deep clones, merges, updates and projects queries. Targets .NET 3.5+ and .NET Standard 1.0+ - Mapper, Mapping, Mappings, ViewModel, DTO, NetStandard + Mapper, Mapping, ViewModel, DTO https://github.com/AgileObjects/AgileMapper - 1.6.1 - $(PackageTargetFallback);dnxcore50 MIT ./Icon.png - - Adding .NET Standard 2.0 target -- Support for configuring data sources by matcher, re: #208 -- Fixing potential cache threading issue, re: #212 -- Throwing ObjectDisposed on attempt to use disposed Mapper, re: #212 -- Improving target member selection, re: #209 + - Improving surfaced mapping plans +- Improving enum mapping +- Improving non-readable member derived target type mapping +- Improving simple-type enumerable merge and overwrite mapping +- Improving performance and memory use + 2.0.0-preview1 + 2.0.0.0 + 2.0.0.0 + ../NuGet @@ -37,7 +38,7 @@ - + @@ -74,11 +75,11 @@ - $(DefineConstants);FEATURE_SERIALIZATION;FEATURE_DYNAMIC;FEATURE_DYNAMIC_ROOT_SOURCE;FEATURE_ISET + $(DefineConstants);FEATURE_SERIALIZATION;FEATURE_DYNAMIC;FEATURE_DYNAMIC_ROOT_SOURCE;FEATURE_ISET;FEATURE_ARRAY_EMPTY - $(DefineConstants);FEATURE_SERIALIZATION;FEATURE_DYNAMIC;FEATURE_DYNAMIC_ROOT_SOURCE;FEATURE_ISET;FEATURE_APPDOMAIN;FEATURE_ASSEMBLY_TRUST + $(DefineConstants);FEATURE_SERIALIZATION;FEATURE_DYNAMIC;FEATURE_DYNAMIC_ROOT_SOURCE;FEATURE_ISET;FEATURE_APPDOMAIN;FEATURE_ASSEMBLY_TRUST;FEATURE_ARRAY_EMPTY diff --git a/AgileMapper/Api/Configuration/ConfigInfoDataSourceExtensions.cs b/AgileMapper/Api/Configuration/ConfigInfoDataSourceExtensions.cs index 33f252f4b..ba68e9d3d 100644 --- a/AgileMapper/Api/Configuration/ConfigInfoDataSourceExtensions.cs +++ b/AgileMapper/Api/Configuration/ConfigInfoDataSourceExtensions.cs @@ -5,7 +5,7 @@ using System.Linq.Expressions; using AgileMapper.Configuration; using Extensions.Internal; - using Members; + using Members.Extensions; using ReadableExpressions; internal static class ConfigInfoDataSourceExtensions diff --git a/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs b/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs index 22b24920c..08179c257 100644 --- a/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs +++ b/AgileMapper/Api/Configuration/CustomDataSourceTargetMemberSpecifier.cs @@ -14,6 +14,7 @@ using Extensions.Internal; using Members; using Members.Dictionaries; + using Members.Extensions; using NetStandardPolyfills; using Projection; using ReadableExpressions; @@ -250,7 +251,7 @@ private ConfiguredLambdaInfo GetValueLambdaInfo(Type targetValueType) return _customValueLambdaInfo = ConfiguredLambdaInfo.For(customValueLambda, _configInfo); } - var convertedConstantValue = MapperContext + var convertedConstantValue = _configInfo .GetValueConversion(customValueLambda.Body, targetValueType); var funcType = Expr.GetFuncType(targetValueType); diff --git a/AgileMapper/Api/Configuration/Dictionaries/TargetDictionaryMappingConfigurator.cs b/AgileMapper/Api/Configuration/Dictionaries/TargetDictionaryMappingConfigurator.cs index 695787b7d..3140048e1 100644 --- a/AgileMapper/Api/Configuration/Dictionaries/TargetDictionaryMappingConfigurator.cs +++ b/AgileMapper/Api/Configuration/Dictionaries/TargetDictionaryMappingConfigurator.cs @@ -5,6 +5,7 @@ namespace AgileObjects.AgileMapper.Api.Configuration.Dictionaries using System.Linq.Expressions; using AgileMapper.Configuration; using Members; + using Members.Extensions; using ReadableExpressions; internal class TargetDictionaryMappingConfigurator : diff --git a/AgileMapper/Api/Configuration/Dynamics/TargetDynamicMappingConfigurator.cs b/AgileMapper/Api/Configuration/Dynamics/TargetDynamicMappingConfigurator.cs index 99f8c5ed7..4b515bb01 100644 --- a/AgileMapper/Api/Configuration/Dynamics/TargetDynamicMappingConfigurator.cs +++ b/AgileMapper/Api/Configuration/Dynamics/TargetDynamicMappingConfigurator.cs @@ -7,6 +7,7 @@ namespace AgileObjects.AgileMapper.Api.Configuration.Dynamics using AgileMapper.Configuration; using Dictionaries; using Members; + using Members.Extensions; using ReadableExpressions; internal class TargetDynamicMappingConfigurator : diff --git a/AgileMapper/Api/Configuration/EventConfigStartingPointBase.cs b/AgileMapper/Api/Configuration/EventConfigStartingPointBase.cs index eca7ccfc6..e03e56b79 100644 --- a/AgileMapper/Api/Configuration/EventConfigStartingPointBase.cs +++ b/AgileMapper/Api/Configuration/EventConfigStartingPointBase.cs @@ -3,6 +3,7 @@ using System.Linq.Expressions; using AgileMapper.Configuration; using Members; + using Members.Extensions; /// /// Provides options for configuring an element of how this mapper performs a mapping. diff --git a/AgileMapper/Api/Configuration/FactorySpecifier.cs b/AgileMapper/Api/Configuration/FactorySpecifier.cs index 5f8ca8409..761d3f2e0 100644 --- a/AgileMapper/Api/Configuration/FactorySpecifier.cs +++ b/AgileMapper/Api/Configuration/FactorySpecifier.cs @@ -16,7 +16,6 @@ namespace AgileObjects.AgileMapper.Api.Configuration #else using LambdaExpr = System.Linq.Expressions.LambdaExpression; #endif - using static ObjectPopulation.InvocationPosition; internal class FactorySpecifier : IMappingFactorySpecifier, diff --git a/AgileMapper/Api/Configuration/InstanceConfigurator.cs b/AgileMapper/Api/Configuration/InstanceConfigurator.cs index 519401416..6b3f26d49 100644 --- a/AgileMapper/Api/Configuration/InstanceConfigurator.cs +++ b/AgileMapper/Api/Configuration/InstanceConfigurator.cs @@ -9,6 +9,7 @@ namespace AgileObjects.AgileMapper.Api.Configuration using System.Linq.Expressions; using ReadableExpressions; using ReadableExpressions.Extensions; + using TypeConversion; #if NET35 using static Microsoft.Scripting.Ast.Expression; using Expression = Microsoft.Scripting.Ast.Expression; @@ -140,7 +141,7 @@ private Expression GetStringIdPart(Expression idPart) { if (idPart.Type != typeof(string)) { - idPart = _configInfo.MapperContext.GetValueConversion(idPart, typeof(string)); + idPart = _configInfo.GetValueConversion(idPart, typeof(string)); } var idPartNestedAccessesChecks = _configInfo diff --git a/AgileMapper/Api/Configuration/MapperConfigurationSpecifier.cs b/AgileMapper/Api/Configuration/MapperConfigurationSpecifier.cs index aad0e03e3..55fe48443 100644 --- a/AgileMapper/Api/Configuration/MapperConfigurationSpecifier.cs +++ b/AgileMapper/Api/Configuration/MapperConfigurationSpecifier.cs @@ -330,7 +330,7 @@ private static void ThrowIfInvalidAssemblySupplied(Assembly assembly) private static MappingConfigurationException NullAssemblySupplied(string message) { // ReSharper disable once NotResolvedInText - return new MappingConfigurationException(message, new ArgumentNullException("assemblies")); + return new(message, new ArgumentNullException("assemblies")); } private static bool AllAssemblies(Assembly assembly) => true; diff --git a/AgileMapper/Api/IPlanTargetAndRuleSetSelector.cs b/AgileMapper/Api/IPlanTargetAndRuleSetSelector.cs index ea606ae68..3d9f00193 100644 --- a/AgileMapper/Api/IPlanTargetAndRuleSetSelector.cs +++ b/AgileMapper/Api/IPlanTargetAndRuleSetSelector.cs @@ -32,35 +32,37 @@ MappingPlan ToANew( params Expression>>[] configurations); /// - /// Create and compile mapping functions for an OnTo (merge) mapping from the source type being - /// configured to the type specified by the type argument. + /// Create and compile mapping functions for an OnTo (merge) mapping from the source type + /// being configured to the type specified by the type argument. /// /// The type of object for which to create the mapping plan. /// - /// Zero or more mapping configurations. If supplied, the mapping functions will be configured by - /// combining these inline with any configuration already set up - /// via the Mapper.WhenMapping API. + /// Zero or more mapping configurations. If supplied, the mapping functions will be + /// configured by combining these inline with any + /// configuration already set up via the Mapper.WhenMapping API. /// /// - /// A object detailing the function to be executed during a mapping. To see - /// a string representation of the function assign the result to a string variable, or call .ToString(). + /// A object detailing the function to be executed during a mapping. + /// To see a string representation of the function assign the result to a string variable, + /// or call .ToString(). /// MappingPlan OnTo( params Expression>>[] configurations); /// - /// Create and compile mapping functions for an Over (overwrite) mapping from the source type being - /// configured to the type specified by the type argument. + /// Create and compile mapping functions for an Over (overwrite) mapping from the source type + /// being configured to the type specified by the type argument. /// /// The type of object for which to create the mapping plan. /// - /// Zero or more mapping configurations. If supplied, the mapping functions will be configured by - /// combining these inline with any configuration already set up - /// via the Mapper.WhenMapping API. + /// Zero or more mapping configurations. If supplied, the mapping functions will be + /// configured by combining these inline with any + /// configuration already set up via the Mapper.WhenMapping API. /// /// - /// A object detailing the function to be executed during a mapping. To see - /// a string representation of the function assign the result to a string variable, or call .ToString(). + /// A object detailing the function to be executed during a mapping. + /// To see a string representation of the function assign the result to a string variable, + /// or call .ToString(). /// MappingPlan Over( params Expression>>[] configurations); diff --git a/AgileMapper/Api/PlanTargetSelector.cs b/AgileMapper/Api/PlanTargetSelector.cs index 479c78b07..a206b1812 100644 --- a/AgileMapper/Api/PlanTargetSelector.cs +++ b/AgileMapper/Api/PlanTargetSelector.cs @@ -11,7 +11,8 @@ using ObjectPopulation; using Plans; using Queryables.Api; - + using static Plans.MappingPlanSettings.Default; + internal class PlanTargetSelector : IPlanTargetSelector, IPlanTargetAndRuleSetSelector, @@ -31,50 +32,62 @@ internal PlanTargetSelector(MapperContext mapperContext) _mapperContext = mapperContext.ThrowIfDisposed(); } - public MappingPlanSet To() => To(configurations: null); + public MappingPlanSet To() + => To(configurations: Enumerable>>>.EmptyArray); public MappingPlanSet To( Expression>>[] configurations) { - return new MappingPlanSet( - _mapperContext - .RuleSets - .All - .Filter(_mapperContext, (mc, ruleSet) => ruleSet != mc.RuleSets.Project) - .Project(configurations, (cs, rs) => GetMappingPlan(rs, cs)) - .ToArray()); + return new(_mapperContext + .RuleSets + .All + .Filter(_mapperContext, (mc, ruleSet) => ruleSet != mc.RuleSets.Project) + .Project(configurations, (cs, rs) => GetMappingPlan(rs, EagerPlanned, cs)) + .ToArray()); } public MappingPlan ToANew( Expression>>[] configurations) - => GetMappingPlan(_mapperContext.RuleSets.CreateNew, configurations); + { + return GetMappingPlan( + _mapperContext.RuleSets.CreateNew, + EagerPlanned, + configurations); + } public MappingPlan OnTo( Expression>>[] configurations) - => GetMappingPlan(_mapperContext.RuleSets.Merge, configurations); + { + return GetMappingPlan( + _mapperContext.RuleSets.Merge, + EagerPlanned, + configurations); + } public MappingPlan Over( Expression>>[] configurations) - => GetMappingPlan(_mapperContext.RuleSets.Overwrite, configurations); + { + return GetMappingPlan( + _mapperContext.RuleSets.Overwrite, + EagerPlanned, + configurations); + } MappingPlan IProjectionPlanTargetSelector.To() { - return GetMappingPlan( + return GetMappingPlan( _mapperContext.QueryProjectionMappingContext, - planContext => ObjectMappingDataFactory.ForProjection(_exampleQueryable, planContext)); + planContext => ObjectMappingDataFactory.ForProjection(_exampleQueryable, planContext), + Enumerable>>>.EmptyArray); } private MappingPlan GetMappingPlan( MappingRuleSet ruleSet, + MappingPlanSettings settings, ICollection>>> configurations) { - var planContext = new SimpleMappingContext(ruleSet, _mapperContext) - { - IgnoreUnsuccessfulMemberPopulations = false - }; - return GetMappingPlan( - planContext, + new SimpleMappingContext(ruleSet, settings, _mapperContext), ObjectMappingDataFactory.ForRootFixedTypes, configurations); } @@ -82,9 +95,9 @@ private MappingPlan GetMappingPlan( private static MappingPlan GetMappingPlan( IMappingContext planContext, Func mappingDataFactory, - ICollection>>> configurations = null) + ICollection>>> configurations) { - if (configurations?.Any() == true) + if (configurations.Any()) { InlineMappingConfigurator #if NET35 diff --git a/AgileMapper/Caching/DefaultArrayCache.cs b/AgileMapper/Caching/DefaultArrayCache.cs index 8d2811c8c..b4dd4d72f 100644 --- a/AgileMapper/Caching/DefaultArrayCache.cs +++ b/AgileMapper/Caching/DefaultArrayCache.cs @@ -23,7 +23,7 @@ protected override bool TryGetValue(TKey key, int length, out TValue value) { - for (var i = startIndex; i < length; i++) + for (var i = startIndex; i < length; ++i) { var thisKey = _keys[i]; diff --git a/AgileMapper/Configuration/DataSources/ConfiguredDataSourceFactory.cs b/AgileMapper/Configuration/DataSources/ConfiguredDataSourceFactory.cs index 5b792bab2..b49577e7a 100644 --- a/AgileMapper/Configuration/DataSources/ConfiguredDataSourceFactory.cs +++ b/AgileMapper/Configuration/DataSources/ConfiguredDataSourceFactory.cs @@ -7,6 +7,7 @@ #endif using Lambdas; using Members; + using Members.Extensions; internal class ConfiguredDataSourceFactory : ConfiguredDataSourceFactoryBase, diff --git a/AgileMapper/Configuration/DataSources/ConfiguredDataSourceFactoryBase.cs b/AgileMapper/Configuration/DataSources/ConfiguredDataSourceFactoryBase.cs index 4e4d518bb..c15d75892 100644 --- a/AgileMapper/Configuration/DataSources/ConfiguredDataSourceFactoryBase.cs +++ b/AgileMapper/Configuration/DataSources/ConfiguredDataSourceFactoryBase.cs @@ -10,6 +10,7 @@ using Api.Configuration; using Lambdas; using Members; + using Members.Extensions; internal abstract class ConfiguredDataSourceFactoryBase : UserConfiguredItemBase, diff --git a/AgileMapper/Configuration/Dictionaries/CustomDictionaryKey.cs b/AgileMapper/Configuration/Dictionaries/CustomDictionaryKey.cs index 169df066d..b7a3a1bb8 100644 --- a/AgileMapper/Configuration/Dictionaries/CustomDictionaryKey.cs +++ b/AgileMapper/Configuration/Dictionaries/CustomDictionaryKey.cs @@ -9,6 +9,7 @@ #endif using DataSources; using Members; + using Members.Extensions; using ReadableExpressions.Extensions; internal class CustomDictionaryKey : UserConfiguredItemBase @@ -105,8 +106,8 @@ private static bool IsPartOfExpandoObjectMapping(IQualifiedMemberContext context { while (context != null) { - if ((context.SourceMember.GetFriendlyTypeName() == nameof(ExpandoObject)) || - (context.TargetMember.GetFriendlyTypeName() == nameof(ExpandoObject))) + if ((context.SourceMember.GetTypeName() == nameof(ExpandoObject)) || + (context.TargetMember.GetTypeName() == nameof(ExpandoObject))) { return true; } diff --git a/AgileMapper/Configuration/Dictionaries/ElementKeyPartFactory.cs b/AgileMapper/Configuration/Dictionaries/ElementKeyPartFactory.cs index 16d2df72c..d4a2ac7c4 100644 --- a/AgileMapper/Configuration/Dictionaries/ElementKeyPartFactory.cs +++ b/AgileMapper/Configuration/Dictionaries/ElementKeyPartFactory.cs @@ -15,6 +15,7 @@ using Members; using NetStandardPolyfills; using ReadableExpressions.Extensions; + using TypeConversion; internal class ElementKeyPartFactory : DictionaryKeyPartFactoryBase { @@ -126,16 +127,24 @@ private static MappingConfigurationException InvalidPattern() private string Pattern => _prefixString + "i" + _suffixString; public Expression GetElementKeyPartMatcher() - => _keyPartMatcher ??= CreateKeyPartRegex().ToConstantExpression(); + => _keyPartMatcher ??= CreateKeyPartRegexPattern().ToConstantExpression(); - private Regex CreateKeyPartRegex() + private string CreateKeyPartRegexPattern() + => GetTokenForRegex(_prefixString) + "[0-9]+" + GetTokenForRegex(_suffixString); + + private static string GetTokenForRegex(string value) { - return new Regex( - _prefixString + "[0-9]+" + _suffixString -#if !NETSTANDARD1_0 - , RegexOptions.Compiled -#endif - ); + switch (value) + { + case "[": + case "]": + case "(": + case ")": + return '\\' + value; + + default: + return value; + } } public Expression GetElementKeyPrefixOrNull() => _prefix; @@ -163,7 +172,7 @@ public IEnumerable GetElementKeyParts(Expression index) yield return _prefix; } - yield return ConfigInfo.MapperContext.GetValueConversion(index, typeof(string)); + yield return ConfigInfo.GetValueConversion(index, typeof(string)); if (_suffix != null) { diff --git a/AgileMapper/Configuration/EnumComparisonFixer.cs b/AgileMapper/Configuration/EnumComparisonFixer.cs index 60bb522da..f85cea55f 100644 --- a/AgileMapper/Configuration/EnumComparisonFixer.cs +++ b/AgileMapper/Configuration/EnumComparisonFixer.cs @@ -9,7 +9,6 @@ using Caching.Dictionaries; using Extensions.Internal; using NetStandardPolyfills; - using ReadableExpressions.Extensions; internal class EnumComparisonFixer : ExpressionVisitor { diff --git a/AgileMapper/Configuration/Lambdas/ConfiguredLambdaInfo.cs b/AgileMapper/Configuration/Lambdas/ConfiguredLambdaInfo.cs index d640694f4..d9dbce6e4 100644 --- a/AgileMapper/Configuration/Lambdas/ConfiguredLambdaInfo.cs +++ b/AgileMapper/Configuration/Lambdas/ConfiguredLambdaInfo.cs @@ -10,6 +10,7 @@ using Extensions.Internal; using Members; using Members.Dictionaries; + using Members.Extensions; using NetStandardPolyfills; using ReadableExpressions; using ReadableExpressions.Extensions; @@ -102,7 +103,7 @@ public static ConfiguredLambdaInfo ForAction( configInfo, argumentTypes, funcTypes => funcTypes, - funcTypes => typeof(void), + _ => typeof(void), typeof(Action<>), typeof(Action<,>), typeof(Action<,,>), @@ -174,7 +175,7 @@ public bool TryGetSourceMember(out LambdaExpression sourceMemberLambda) return IsNotSourceMember(out sourceMemberLambda); } - var memberAccesses = _lambdaBody.GetMemberAccessChain(nt => { }, out var rootExpression); + var memberAccesses = _lambdaBody.GetMemberAccessChain(_ => { }, out var rootExpression); if (memberAccesses.None()) { diff --git a/AgileMapper/Configuration/MapToNullCondition.cs b/AgileMapper/Configuration/MapToNullCondition.cs index 93272e394..503cf8a12 100644 --- a/AgileMapper/Configuration/MapToNullCondition.cs +++ b/AgileMapper/Configuration/MapToNullCondition.cs @@ -1,13 +1,12 @@ namespace AgileObjects.AgileMapper.Configuration { using System; - using Members; - using ObjectPopulation; #if NET35 using Microsoft.Scripting.Ast; #else using System.Linq.Expressions; #endif + using Members; internal class MapToNullCondition : UserConfiguredItemBase diff --git a/AgileMapper/Configuration/MapperConfiguration.cs b/AgileMapper/Configuration/MapperConfiguration.cs index 2d46b2469..20cad6111 100644 --- a/AgileMapper/Configuration/MapperConfiguration.cs +++ b/AgileMapper/Configuration/MapperConfiguration.cs @@ -108,8 +108,11 @@ protected IPlanTargetAndRuleSetSelector GetPlanFor() /// An IProjectionPlanTargetSelector with which to specify the target Type to which the query projection function to /// be created should be cached. /// - protected IProjectionPlanTargetSelector GetPlanForProjecting(IQueryable exampleQueryable) - => _mapper.GetPlanForProjecting(exampleQueryable); + protected IProjectionPlanTargetSelector GetPlanForProjecting( + IQueryable exampleQueryable) + { + return _mapper.GetPlanForProjecting(exampleQueryable); + } /// /// Create and compile mapping functions for mapping from the source type specified by the given diff --git a/AgileMapper/Configuration/MappingConfigInfo.cs b/AgileMapper/Configuration/MappingConfigInfo.cs index 68e926281..28621a75b 100644 --- a/AgileMapper/Configuration/MappingConfigInfo.cs +++ b/AgileMapper/Configuration/MappingConfigInfo.cs @@ -24,7 +24,7 @@ internal delegate bool TargetTypeComparer(ITypePair typePair, ITypePair otherTypePair); - internal class MappingConfigInfo : ITypePair + internal class MappingConfigInfo : IMapperContextOwner, IRuleSetOwner, ITypePair { public static readonly MappingConfigInfo AllRuleSetsSourceTypesAndTargetTypes = AllRuleSetsAndSourceTypes(null).ForAllTargetTypes(); diff --git a/AgileMapper/Configuration/MemberIgnores/ConfiguredSourceMemberIgnore.cs b/AgileMapper/Configuration/MemberIgnores/ConfiguredSourceMemberIgnore.cs index dc1e7317a..8a6d7a582 100644 --- a/AgileMapper/Configuration/MemberIgnores/ConfiguredSourceMemberIgnore.cs +++ b/AgileMapper/Configuration/MemberIgnores/ConfiguredSourceMemberIgnore.cs @@ -10,6 +10,7 @@ namespace AgileObjects.AgileMapper.Configuration.MemberIgnores using Extensions.Internal; #endif using Members; + using Members.Extensions; #if NET35 using LinqExp = System.Linq.Expressions; #endif diff --git a/AgileMapper/Configuration/MemberIgnores/SourceValueFilters/FilterCondition.cs b/AgileMapper/Configuration/MemberIgnores/SourceValueFilters/FilterCondition.cs index 861274d08..a75caff1a 100644 --- a/AgileMapper/Configuration/MemberIgnores/SourceValueFilters/FilterCondition.cs +++ b/AgileMapper/Configuration/MemberIgnores/SourceValueFilters/FilterCondition.cs @@ -9,9 +9,8 @@ namespace AgileObjects.AgileMapper.Configuration.MemberIgnores.SourceValueFilter #endif using Api.Configuration; using Extensions.Internal; - using Members.MemberExtensions; + using Members.Extensions; using NetStandardPolyfills; - using ReadableExpressions.Extensions; #if NET35 using LinqExp = System.Linq.Expressions; #endif diff --git a/AgileMapper/Configuration/UserConfiguredItemBase.cs b/AgileMapper/Configuration/UserConfiguredItemBase.cs index 747eead86..4dab837ad 100644 --- a/AgileMapper/Configuration/UserConfiguredItemBase.cs +++ b/AgileMapper/Configuration/UserConfiguredItemBase.cs @@ -7,6 +7,7 @@ using System.Linq.Expressions; #endif using Members; + using Members.Extensions; using NetStandardPolyfills; using ReadableExpressions.Extensions; diff --git a/AgileMapper/DataSources/ComplexTypeDataSource.cs b/AgileMapper/DataSources/ComplexTypeDataSource.cs index d8f6732c9..2a27f0a9f 100644 --- a/AgileMapper/DataSources/ComplexTypeDataSource.cs +++ b/AgileMapper/DataSources/ComplexTypeDataSource.cs @@ -6,6 +6,7 @@ using System.Linq.Expressions; #endif using Members; + using Members.Extensions; using ObjectPopulation; using ObjectPopulation.ComplexTypes; diff --git a/AgileMapper/DataSources/ConfiguredMappingDataSource.cs b/AgileMapper/DataSources/ConfiguredMappingDataSource.cs index 930358c79..6e0b64a3e 100644 --- a/AgileMapper/DataSources/ConfiguredMappingDataSource.cs +++ b/AgileMapper/DataSources/ConfiguredMappingDataSource.cs @@ -6,6 +6,7 @@ using System.Linq.Expressions; #endif using Members; + using Members.Extensions; using ObjectPopulation; internal static class ConfiguredMappingDataSource diff --git a/AgileMapper/DataSources/DataSourceBase.cs b/AgileMapper/DataSources/DataSourceBase.cs index 81ddf523f..ea0dd0740 100644 --- a/AgileMapper/DataSources/DataSourceBase.cs +++ b/AgileMapper/DataSources/DataSourceBase.cs @@ -8,6 +8,7 @@ #endif using Extensions.Internal; using Members; + using Members.Extensions; using NetStandardPolyfills; using Optimisation; diff --git a/AgileMapper/DataSources/DataSourceFilteringExtensions.cs b/AgileMapper/DataSources/DataSourceFilteringExtensions.cs index e2c379c6c..86a6d713b 100644 --- a/AgileMapper/DataSources/DataSourceFilteringExtensions.cs +++ b/AgileMapper/DataSources/DataSourceFilteringExtensions.cs @@ -9,6 +9,7 @@ using Configuration.MemberIgnores.SourceValueFilters; using Extensions.Internal; using Members; + using Members.Extensions; internal static class DataSourceFilteringExtensions { diff --git a/AgileMapper/DataSources/DataSourceSet.cs b/AgileMapper/DataSources/DataSourceSet.cs index b87727918..1cca7d34c 100644 --- a/AgileMapper/DataSources/DataSourceSet.cs +++ b/AgileMapper/DataSources/DataSourceSet.cs @@ -24,7 +24,7 @@ private static IDataSourceSet For( { if (!dataSource.IsValid) { - return info.MappingContext.IgnoreUnsuccessfulMemberPopulations + return info.MappingContext.PlanSettings.CommentUnmappedMembers ? EmptyDataSourceSet.Instance : new NullDataSourceSet(dataSource); } diff --git a/AgileMapper/DataSources/DictionaryNonSimpleMemberDataSource.cs b/AgileMapper/DataSources/DictionaryNonSimpleMemberDataSource.cs index 16693e0d3..589e36cf0 100644 --- a/AgileMapper/DataSources/DictionaryNonSimpleMemberDataSource.cs +++ b/AgileMapper/DataSources/DictionaryNonSimpleMemberDataSource.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.DataSources { using Members; + using Members.Extensions; internal class DictionaryNonSimpleMemberDataSource : DataSourceBase { diff --git a/AgileMapper/DataSources/Factories/DerivedComplexTypeDataSourcesFactory.cs b/AgileMapper/DataSources/Factories/DerivedComplexTypeDataSourcesFactory.cs index 350ada91d..27c7d3721 100644 --- a/AgileMapper/DataSources/Factories/DerivedComplexTypeDataSourcesFactory.cs +++ b/AgileMapper/DataSources/Factories/DerivedComplexTypeDataSourcesFactory.cs @@ -5,10 +5,8 @@ using System.Linq; #if NET35 using Microsoft.Scripting.Ast; - using static Microsoft.Scripting.Ast.Expression; #else using System.Linq.Expressions; - using static System.Linq.Expressions.Expression; #endif using Configuration; using Extensions; @@ -17,6 +15,11 @@ using NetStandardPolyfills; using ObjectPopulation; using ReadableExpressions; +#if NET35 + using static Microsoft.Scripting.Ast.Expression; +#else + using static System.Linq.Expressions.Expression; +#endif using static Constants; using static TypeComparer; @@ -263,7 +266,7 @@ private static void AddDerivedSourceTypeDataSources( groupedTypePairs, targetType); - AddDataSourceIfValid: + AddDataSourceIfValid: if (sourceVariableIsDerivedTypeDataSource.IsValid) { derivedTypeDataSources.Insert(sourceVariableIsDerivedTypeDataSource, insertionOffset); @@ -450,18 +453,25 @@ private static IList GetTypePairsFor( } private static void AddDerivedTargetTypeDataSources( - IEnumerable derivedTargetTypes, + ICollection derivedTargetTypes, IObjectMappingData declaredTypeMappingData, ICollection derivedTypeDataSources) { var declaredTypeMapperData = declaredTypeMappingData.MapperData; - if (((ICollection)derivedTargetTypes).Count > 1) + if (declaredTypeMapperData.TargetMemberNullOrInaccessible()) + { + return; + } + + IEnumerable orderedDerivedTargetTypes = derivedTargetTypes; + + if (derivedTargetTypes.Count > 1) { - derivedTargetTypes = derivedTargetTypes.OrderBy(t => t, MostToLeastDerived); + orderedDerivedTargetTypes = orderedDerivedTargetTypes.OrderBy(t => t, MostToLeastDerived); } - foreach (var derivedTargetType in derivedTargetTypes) + foreach (var derivedTargetType in orderedDerivedTargetTypes) { var targetTypeCondition = declaredTypeMapperData.GetTargetIsDerivedTypeCheck(derivedTargetType); @@ -524,7 +534,7 @@ private static Expression GetReturnMappingResultExpression( private static Expression GetTargetValidCheckOrNull(this IMemberMapperData mapperData, Type targetType) { - if (!mapperData.TargetMember.IsReadable || mapperData.TargetIsDefinitelyUnpopulated()) + if (mapperData.TargetMemberNullOrInaccessible()) { return null; } @@ -542,6 +552,9 @@ private static Expression GetTargetValidCheckOrNull(this IMemberMapperData mappe return targetIsValid; } + private static bool TargetMemberNullOrInaccessible(this IMemberMapperData mapperData) + => !mapperData.TargetMember.IsReadable || mapperData.TargetIsDefinitelyUnpopulated(); + private static Expression GetTargetIsDerivedTypeCheck(this IMemberMapperData mapperData, Type targetType) => TypeIs(mapperData.TargetObject, targetType); @@ -553,7 +566,7 @@ public DerivedComplexTypeDataSource( IQualifiedMember sourceMember, Expression condition, Expression value) - : base(sourceMember, Constants.EmptyParameters, value, condition) + : base(sourceMember, EmptyParameters, value, condition) { } diff --git a/AgileMapper/DataSources/Factories/Mapping/RootEnumMappingDataSourceFactory.cs b/AgileMapper/DataSources/Factories/Mapping/RootEnumMappingDataSourceFactory.cs index 27fb5c4a0..0ffe574d2 100644 --- a/AgileMapper/DataSources/Factories/Mapping/RootEnumMappingDataSourceFactory.cs +++ b/AgileMapper/DataSources/Factories/Mapping/RootEnumMappingDataSourceFactory.cs @@ -2,7 +2,6 @@ { using NetStandardPolyfills; using ObjectPopulation; - using ReadableExpressions.Extensions; internal class RootEnumMappingDataSourceFactory : MappingDataSourceFactoryBase { diff --git a/AgileMapper/DataSources/Optimisation/MultiInvocationsFinder.cs b/AgileMapper/DataSources/Optimisation/MultiInvocationsFinder.cs index 0f37b1e10..2c3cd9434 100644 --- a/AgileMapper/DataSources/Optimisation/MultiInvocationsFinder.cs +++ b/AgileMapper/DataSources/Optimisation/MultiInvocationsFinder.cs @@ -9,7 +9,7 @@ #endif using Extensions.Internal; using Members; - using Members.MemberExtensions; + using Members.Extensions; internal static class MultiInvocationsFinder { diff --git a/AgileMapper/Enumerable.cs b/AgileMapper/Enumerable.cs index 867094337..197674015 100644 --- a/AgileMapper/Enumerable.cs +++ b/AgileMapper/Enumerable.cs @@ -1,5 +1,8 @@ namespace AgileObjects.AgileMapper { +#if FEATURE_ARRAY_EMPTY + using System; +#endif using System.Collections.Generic; /// @@ -11,7 +14,12 @@ public static class Enumerable /// /// Gets a singleton empty array instance. /// - public static readonly TElement[] EmptyArray = { }; + public static readonly TElement[] EmptyArray = +#if FEATURE_ARRAY_EMPTY + Array.Empty(); +#else + { }; +#endif /// /// Gets a singleton empty array instance. diff --git a/AgileMapper/Extensions/Internal/EnumerableExtensions.cs b/AgileMapper/Extensions/Internal/EnumerableExtensions.cs index 88a4a030a..ba70e0f31 100644 --- a/AgileMapper/Extensions/Internal/EnumerableExtensions.cs +++ b/AgileMapper/Extensions/Internal/EnumerableExtensions.cs @@ -59,7 +59,7 @@ public static T First(this IList items, TArg argument, Func(this IList items, Func predicate) - => FirstOrDefault(items, predicate, (p, item) => predicate.Invoke(item)); + => FirstOrDefault(items, predicate, (_, item) => predicate.Invoke(item)); [DebuggerStepThrough] public static T FirstOrDefault(this IList items, TArg argument, Func predicate) @@ -80,11 +80,11 @@ public static IEnumerable TakeUntil(this IEnumerable items, Func(this IList items, Func predicate, out T match) - => TryFindMatch(items, predicate, (p, item) => p.Invoke(item), out match); - - [DebuggerStepThrough] - public static bool TryFindMatch(this IList items, TArg argument, Func predicate, out T match) + public static bool TryFindMatch( + this IList items, + TArg argument, + Func predicate, + out T match) { for (int i = 0, n = items.Count; i < n; ++i) { @@ -100,6 +100,26 @@ public static bool TryFindMatch(this IList items, TArg argument, Fun return false; } + [DebuggerStepThrough] + public static bool TryFindMatch( + this IEnumerable items, + TArg argument, + Func predicate, + out T match) + { + foreach (var item in items) + { + if (predicate.Invoke(argument, item)) + { + match = item; + return true; + } + } + + match = default; + return false; + } + [DebuggerStepThrough] public static T Last(this IList items) => items[items.Count - 1]; diff --git a/AgileMapper/Extensions/Internal/ExpressionExtensions.cs b/AgileMapper/Extensions/Internal/ExpressionExtensions.cs index 0a1984038..5d37f438d 100644 --- a/AgileMapper/Extensions/Internal/ExpressionExtensions.cs +++ b/AgileMapper/Extensions/Internal/ExpressionExtensions.cs @@ -96,6 +96,11 @@ public static LoopExpression InsertAssignment( ParameterExpression variable, Expression value) { + if (variable == value) + { + return loop; + } + var loopBody = (BlockExpression)loop.Body; var loopBodyExpressions = new Expression[loopBody.Expressions.Count + 1]; var expressionOffset = 0; @@ -322,16 +327,24 @@ public static Expression GetRootExpression(this Expression expression) public static Expression ToExpression(this IList expressions) => expressions.HasOne() ? expressions.First() : Expression.Block(expressions); - public static IList GetMemberMappingExpressions(this IList mappingExpressions) - => mappingExpressions.Filter(IsMemberMapping).ToList(); + public static IEnumerable EnumerateMappingExpressions( + this IList mappingExpressions, + bool includeCallbacks) + { + return mappingExpressions + .Filter(includeCallbacks, (inc, exp) => IsMappingExpression(exp, inc)); + } - private static bool IsMemberMapping(Expression expression) + private static bool IsMappingExpression(Expression expression, bool includeCallbacks) { switch (expression.NodeType) { case Constant: return false; + case Invoke: + return includeCallbacks; + case Call when ( IsCallTo(nameof(IObjectMappingDataUntyped.Register), expression) || IsCallTo(nameof(IObjectMappingDataUntyped.TryGet), expression)): @@ -354,9 +367,18 @@ private static bool IsMapRepeatedCall(Expression expression) private static bool IsCallTo(string methodName, Expression call) => ((MethodCallExpression)call).Method.Name == methodName; - public static bool TryGetVariableAssignment(this IList mappingExpressions, out BinaryExpression assignment) + public static bool TryGetAssignment( + this IList mappingExpressions, + ParameterExpression variable, + out BinaryExpression assignment) { - if (mappingExpressions.TryFindMatch(exp => exp.NodeType == Assign, out var assignmentExpression)) + var assignmentExists = + EnumerateExpressions(mappingExpressions).TryFindMatch( + variable, + (var, exp) => exp.NodeType == Assign && ((BinaryExpression)exp).Left == var, + out var assignmentExpression); + + if (assignmentExists) { assignment = (BinaryExpression)assignmentExpression; return true; @@ -365,6 +387,25 @@ public static bool TryGetVariableAssignment(this IList mappingExpres assignment = null; return false; } + + private static IEnumerable EnumerateExpressions(IEnumerable expressions) + { + foreach (var expression in expressions) + { + if (expression.NodeType != Block) + { + yield return expression; + continue; + } + + var block = (BlockExpression)expression; + + foreach (var blockExpression in EnumerateExpressions(block.Expressions)) + { + yield return blockExpression; + } + } + } #if NET35 public static LambdaExpression ToDlrExpression(this LinqExp.LambdaExpression linqLambda) => LinqExpressionToDlrExpressionConverter.Convert(linqLambda); diff --git a/AgileMapper/Extensions/Internal/PublicStringExtensions.cs b/AgileMapper/Extensions/Internal/PublicStringExtensions.cs index 5c6407e37..a362ed2cb 100644 --- a/AgileMapper/Extensions/Internal/PublicStringExtensions.cs +++ b/AgileMapper/Extensions/Internal/PublicStringExtensions.cs @@ -13,8 +13,8 @@ public static class PublicStringExtensions /// /// The value from which to get the first character. /// - /// The first character of the value if it has a length of greater than one, otherwise returns - /// . + /// The first character of the value if it has a length of greater than one, otherwise + /// returns . /// public static string FirstOrDefault(this string value) { @@ -27,23 +27,25 @@ public static string FirstOrDefault(this string value) } /// - /// Determines if the matches the given , - /// given the given and . + /// Determines if the matches the given + /// , given the given and Regex + /// . /// /// The subject key for which to make the determination. /// The query key for which to make the determination. /// The separator to use to separate key parts while making the determination. - /// - /// A Regex with which to match element key parts while making the determination. + /// + /// A Regex pattern with which to match element key parts while making the determination. /// /// - /// True if the matches the given , otherwise false. + /// True if the matches the given , + /// otherwise false. /// public static bool MatchesKey( this string subjectKey, string queryKey, string separator, - Regex elementKeyPartMatcher) + string elementKeyPartMatcherPattern) { if (queryKey == null) { @@ -64,7 +66,7 @@ public static bool MatchesKey( return false; } - var elementKeyParts = elementKeyPartMatcher.Matches(queryKey); + var elementKeyParts = Regex.Matches(queryKey, elementKeyPartMatcherPattern); var searchEndIndex = queryKey.Length; diff --git a/AgileMapper/Extensions/Internal/StringExpressionExtensions.cs b/AgileMapper/Extensions/Internal/StringExpressionExtensions.cs index ed54c48fc..efea523af 100644 --- a/AgileMapper/Extensions/Internal/StringExpressionExtensions.cs +++ b/AgileMapper/Extensions/Internal/StringExpressionExtensions.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; - using System.Text.RegularExpressions; using NetStandardPolyfills; #if NET35 using Microsoft.Scripting.Ast; @@ -152,7 +151,7 @@ public static Expression GetMatchesKeyCall( return GetMatchesKeyWithSeparatorCall(stringAccess, keyValue, separator); } - var matcherPattern = ((Regex)((ConstantExpression)elementKeyPartMatcher).Value).ToString(); + var matcherPattern = (string)((ConstantExpression)elementKeyPartMatcher).Value; if (matcherPattern == "[0-9]+") { diff --git a/AgileMapper/Extensions/Internal/TypeExtensions.cs b/AgileMapper/Extensions/Internal/TypeExtensions.cs index d82a9e16c..05c1b56fd 100644 --- a/AgileMapper/Extensions/Internal/TypeExtensions.cs +++ b/AgileMapper/Extensions/Internal/TypeExtensions.cs @@ -36,75 +36,7 @@ public static string GetShortVariableName(this Type type) variableName[0] + variableName.ToCharArray().Skip(1).Filter(char.IsUpper).Join(string.Empty); - shortVariableName = shortVariableName.ToLowerInvariant(); - - return (!type.IsArray && type.IsEnumerable()) - ? shortVariableName.Pluralise() - : shortVariableName; - } - - public static string GetVariableNameInCamelCase(this Type type) => GetVariableName(type).ToCamelCase(); - - public static string GetVariableNameInPascalCase(this Type type) => GetVariableName(type).ToPascalCase(); - - private static string GetVariableName(Type type) - { - if (type.IsArray) - { - return GetVariableName(type.GetElementType()) + "Array"; - } - - var typeIsEnumerable = type.IsEnumerable(); - var typeIsDictionary = typeIsEnumerable && type.IsDictionary(); - var namingType = (typeIsEnumerable && !typeIsDictionary) ? type.GetEnumerableElementType() : type; - var variableName = GetBaseVariableName(namingType); - - if (namingType.IsInterface()) - { - variableName = variableName.Substring(1); - } - - if (namingType.IsGenericType()) - { - variableName = GetGenericTypeVariableName(variableName, namingType); - } - - variableName = RemoveLeadingNonAlphaNumerics(variableName); - - return (typeIsDictionary || !typeIsEnumerable) ? variableName : variableName.Pluralise(); - } - - private static string GetBaseVariableName(Type namingType) - => namingType.IsPrimitive() ? namingType.GetFriendlyName() : namingType.Name; - - private static string GetGenericTypeVariableName(string variableName, Type namingType) - { - var nonNullableType = namingType.GetNonNullableType(); - var genericTypeArguments = namingType.GetGenericTypeArguments(); - - if (nonNullableType != namingType) - { - return "nullable" + genericTypeArguments[0].GetVariableNameInPascalCase(); - } - - variableName = variableName.Substring(0, variableName.IndexOf('`')); - - variableName += genericTypeArguments - .Project(arg => "_" + arg.GetVariableNameInPascalCase()) - .Join(string.Empty); - - return variableName; - } - - private static string RemoveLeadingNonAlphaNumerics(string value) - { - // Anonymous types start with non-alphanumeric characters - while (!char.IsLetterOrDigit(value, 0)) - { - value = value.Substring(1); - } - - return value; + return shortVariableName.ToLowerInvariant(); } public static bool RuntimeTypeNeeded(this Type type) diff --git a/AgileMapper/Extensions/PublicTypeExtensions.cs b/AgileMapper/Extensions/PublicTypeExtensions.cs index 08406207a..b542ee8c6 100644 --- a/AgileMapper/Extensions/PublicTypeExtensions.cs +++ b/AgileMapper/Extensions/PublicTypeExtensions.cs @@ -4,7 +4,6 @@ using System.Reflection; using Internal; using NetStandardPolyfills; - using ReadableExpressions.Extensions; /// /// Provides mapping-related extension methods for Types. These methods support mapping, and are diff --git a/AgileMapper/IMapper.cs b/AgileMapper/IMapper.cs index b2665e6b3..069356b93 100644 --- a/AgileMapper/IMapper.cs +++ b/AgileMapper/IMapper.cs @@ -2,10 +2,12 @@ { using System; using System.Collections.Generic; + using System.Collections.ObjectModel; using System.Linq; using System.Linq.Expressions; using Api; using Api.Configuration; + using Plans; using Queryables.Api; #if NET35 using Expr = Microsoft.Scripting.Ast.Expression; @@ -93,16 +95,21 @@ IProjectionPlanTargetSelector GetPlanForProjecting GetPlansFor(); /// - /// Returns mapping plans for all mapping functions currently cached by the . + /// Returns a containing plans for all mapping functions + /// currently cached by the . /// - /// A string containing the currently-cached functions to be executed during mappings. - string GetPlansInCache(); + /// + /// A containing the currently-cached functions to be executed + /// during mappings. + /// + MappingPlanSet GetPlansInCache(); /// - /// Returns mapping plan Expressions for all mapping functions currently cached by the . + /// Returns mapping plan Expressions for all mapping functions currently cached by the + /// . /// /// An Expression containing the currently-cached functions to be executed during mappings. - Expr GetPlanExpressionsInCache(); + ReadOnlyCollection GetPlanExpressionsInCache(); /// /// Configure callbacks to be executed before a particular type of event occurs for all source diff --git a/AgileMapper/IMappingContext.cs b/AgileMapper/IMappingContext.cs index 065f5a294..86d5d706e 100644 --- a/AgileMapper/IMappingContext.cs +++ b/AgileMapper/IMappingContext.cs @@ -1,9 +1,9 @@ namespace AgileObjects.AgileMapper { + using Plans; + internal interface IMappingContext : IMapperContextOwner, IRuleSetOwner { - bool IgnoreUnsuccessfulMemberPopulations { get; } - - bool LazyLoadRepeatMappingFuncs { get; } + MappingPlanSettings PlanSettings { get; } } } \ No newline at end of file diff --git a/AgileMapper/Mapper.cs b/AgileMapper/Mapper.cs index 4ed84c50b..13acf9ee3 100644 --- a/AgileMapper/Mapper.cs +++ b/AgileMapper/Mapper.cs @@ -2,6 +2,7 @@ { using System; using System.Collections.Generic; + using System.Collections.ObjectModel; using System.Linq; using System.Linq.Expressions; using Api; @@ -16,8 +17,8 @@ #endif /// - /// Provides a configurable mapping service. Create new instances with Mapper.CreateNew or use the default - /// instance via the static Mapper access methods. + /// Provides a configurable mapping service. Create new instances with Mapper.CreateNew or use + /// the default instance via the static Mapper access methods. /// public sealed class Mapper : IMapperInternal { @@ -44,8 +45,9 @@ private Mapper(MapperContext context) #region Static Access Methods /// - /// Create and compile mapping functions for a particular type of mapping of the source type specified by - /// the given . Use this overload for anonymous types. + /// Create and compile mapping functions for a particular type of mapping of the + /// type, as specified by the given + /// . Use this overload for anonymous types. /// /// The type of the given . /// @@ -58,8 +60,8 @@ private Mapper(MapperContext context) public static IPlanTargetAndRuleSetSelector GetPlanFor(TSource exampleInstance) => GetPlanFor(); /// - /// Create and compile mapping functions for a particular type of mapping of the source type - /// specified by the type argument. + /// Create and compile mapping functions for a particular type of mapping of the + /// type. /// /// The source type for which to create the mapping functions. /// @@ -69,9 +71,10 @@ private Mapper(MapperContext context) public static IPlanTargetAndRuleSetSelector GetPlanFor() => Default.GetPlanFor(); /// - /// Create and compile mapping functions for mapping from the source type specified by the given - /// , for all mapping types (create new, merge, overwrite). Use this - /// overload for anonymous types. + /// Create and compile mapping functions for mapping from the + /// type, as specified by the given + /// , for all mapping types (create new, merge, overwrite). + /// Use this overload for anonymous types. /// /// The source type for which to create the mapping functions. /// @@ -84,8 +87,8 @@ private Mapper(MapperContext context) public static IPlanTargetSelector GetPlansFor(TSource exampleInstance) => GetPlansFor(); /// - /// Create and compile mapping functions for the source type specified by the type argument, for all - /// mapping types (create new, merge, overwrite). + /// Create and compile mapping functions for the + /// type, for all mapping types (create new, merge, overwrite). /// /// The source type for which to create the mapping functions. /// @@ -115,16 +118,20 @@ public static IProjectionPlanTargetSelector GetPlanForProjecting } /// - /// Returns mapping plans for all mapping functions currently cached by the default . + /// Returns a containing plans for all mapping functions currently + /// cached by the default . /// - /// A string containing the currently-cached functions to be executed during mappings. - public static string GetPlansInCache() => Default.GetPlansInCache(); + /// + /// A containing the currently-cached functions to be executed + /// during mappings. + /// + public static MappingPlanSet GetPlansInCache() => Default.GetPlansInCache(); /// /// Returns mapping plan Expressions for all mapping functions currently cached by the default . /// /// An Expression containing the currently-cached functions to be executed during mappings. - public static Expr GetPlanExpressionsInCache() => Default.GetPlanExpressionsInCache(); + public static ReadOnlyCollection GetPlanExpressionsInCache() => Default.GetPlanExpressionsInCache(); /// /// Configure callbacks to be executed before a particular type of event occurs for all source @@ -250,9 +257,9 @@ IProjectionPlanTargetSelector IMapper.GetPlanForProjecting IMapper.GetPlansFor() => GetPlan(); - string IMapper.GetPlansInCache() => MappingPlanSet.For(Context); + MappingPlanSet IMapper.GetPlansInCache() => MappingPlanSet.For(Context); - Expr IMapper.GetPlanExpressionsInCache() => MappingPlanSet.For(Context); + ReadOnlyCollection IMapper.GetPlanExpressionsInCache() => MappingPlanSet.For(Context); private PlanTargetSelector GetPlan() => new PlanTargetSelector(Context); @@ -276,16 +283,16 @@ TSource IMapper.DeepClone( } IFlatteningSelector IMapper.Flatten(TSource source) - => new MappingExecutor(source, Context); + => new MappingExecutor(Context, source); IUnflatteningSelector> IMapper.Unflatten(IDictionary source) - => new MappingExecutor>(source, Context); + => new MappingExecutor>(Context, source); IUnflatteningSelector IMapper.Unflatten(QueryString queryString) - => new MappingExecutor(queryString, Context); + => new MappingExecutor(Context, queryString); ITargetSelector IMapper.Map(TSource source) - => new MappingExecutor(source, Context); + => new MappingExecutor(Context, source); #region IDisposable Members diff --git a/AgileMapper/MapperContextExtensions.cs b/AgileMapper/MapperContextExtensions.cs index 433facbcb..ad82955b4 100644 --- a/AgileMapper/MapperContextExtensions.cs +++ b/AgileMapper/MapperContextExtensions.cs @@ -48,8 +48,5 @@ public static Expression GetIdentifierOrNull( public static Member GetIdentifierOrNull(this MapperContext context, Type type) => context.Naming.GetIdentifierOrNull(type); - - public static Expression GetValueConversion(this MapperContext context, Expression value, Type targetType) - => context.ValueConverters.GetConversion(value, targetType); } } diff --git a/AgileMapper/MappingException.cs b/AgileMapper/MappingException.cs index 72afb9f1b..e98897473 100644 --- a/AgileMapper/MappingException.cs +++ b/AgileMapper/MappingException.cs @@ -5,14 +5,15 @@ #if FEATURE_SERIALIZATION using System.Runtime.Serialization; #endif - using Extensions.Internal; - using Members; - using NetStandardPolyfills; #if NET35 using Microsoft.Scripting.Ast; #else using System.Linq.Expressions; #endif + using Extensions.Internal; + using Members; + using Members.Extensions; + using NetStandardPolyfills; /// /// Represents an error that occurred during a mapping. diff --git a/AgileMapper/MappingExecutionContextBase.cs b/AgileMapper/MappingExecutionContextBase.cs new file mode 100644 index 000000000..78d6514b4 --- /dev/null +++ b/AgileMapper/MappingExecutionContextBase.cs @@ -0,0 +1,83 @@ +namespace AgileObjects.AgileMapper +{ + using ObjectPopulation; + using Plans; + + /// + /// Base type providing creation for objects + /// of the type. + /// + /// + /// The type of source objects from which this + /// will perform mappings. + /// + public abstract class MappingExecutionContextBase : IMappingContext + { + private readonly MapperContext _mapperContext; + private readonly TSource _source; + + /// + /// Initializes a new instance of the + /// class with the given object. + /// + /// The source object from which the mapping is to be performed. + protected MappingExecutionContextBase(TSource source) + { + _mapperContext = Mapper.Default.Context.ThrowIfDisposed(); + _source = source; + } + + MapperContext IMapperContextOwner.MapperContext => _mapperContext; + + MappingRuleSet IRuleSetOwner.RuleSet => null; + + MappingPlanSettings IMappingContext.PlanSettings => null; + + /// + /// Creates a root object for this + /// 's source object and the given + /// object. + /// + /// The type of target object to which the mapping is being performed. + /// The target object to which the mapping is being performed. + /// + /// A root object for this + /// 's source object and the given + /// object. + /// + protected IObjectMappingData CreateRootMappingData(TTarget target) + => ObjectMappingDataFactory.ForRootFixedTypes(_source, target, this, createMapper: false); + + /// + /// Creates an object for the given + /// and child objects. + /// + /// The type of source object from which the child mapping is being performed. + /// The type of target object to which the child mapping is being performed. + /// The child source object from which the mapping is being performed. + /// The child target object to which the mapping is being performed. + /// The mapping data parent object of the child object to create. + /// + /// A child object for the given + /// and objects. + /// + protected static IObjectMappingData CreateChildMappingData( + TChildSource source, + TChildTarget target, + IObjectMappingDataUntyped parent) + { + var parentMappingData = (IObjectMappingData)parent; + + var childMappingData = ObjectMappingDataFactory.ForChild( + source, + target, + parentMappingData.GetElementIndex(), + parentMappingData.GetElementKey(), + targetMemberRegistrationName: string.Empty, + dataSourceIndex: 0, + parentMappingData); + + return (IObjectMappingData)childMappingData; + } + } +} \ No newline at end of file diff --git a/AgileMapper/MappingExecutor.cs b/AgileMapper/MappingExecutor.cs index bb7ad085a..bcce2d292 100644 --- a/AgileMapper/MappingExecutor.cs +++ b/AgileMapper/MappingExecutor.cs @@ -11,6 +11,7 @@ using Extensions; using Extensions.Internal; using ObjectPopulation; + using Plans; internal class MappingExecutor : ITargetSelector, @@ -20,19 +21,17 @@ internal class MappingExecutor : { private readonly TSource _source; - public MappingExecutor(TSource source, MapperContext mapperContext) + public MappingExecutor(MapperContext mapperContext, TSource source) { - _source = source; MapperContext = mapperContext.ThrowIfDisposed(); + _source = source; } public MapperContext MapperContext { get; private set; } public MappingRuleSet RuleSet { get; private set; } - public bool IgnoreUnsuccessfulMemberPopulations => true; - - public bool LazyLoadRepeatMappingFuncs => true; + MappingPlanSettings IMappingContext.PlanSettings => MappingPlanSettings.Default.LazyPlanned; #region ToANew Overloads @@ -135,7 +134,7 @@ private TTarget PerformMapping(TTarget target) { // Optimise for the most common scenario: var typedRootMappingData = ObjectMappingDataFactory - .ForRootFixedTypes(_source, target, this); + .ForRootFixedTypes(_source, target, this, createMapper: true); return typedRootMappingData.MapStart(); } @@ -155,7 +154,6 @@ dynamic IFlatteningSelector.ToDynamic( return configurations.Any() ? ToANew(configurations) : ToANew(); } #endif - Dictionary IFlatteningSelector.ToDictionary( params Expression>>>[] configurations) { diff --git a/AgileMapper/Members/ConfiguredSourceMember.cs b/AgileMapper/Members/ConfiguredSourceMember.cs index 9cd842569..6a11ef4a6 100644 --- a/AgileMapper/Members/ConfiguredSourceMember.cs +++ b/AgileMapper/Members/ConfiguredSourceMember.cs @@ -8,9 +8,10 @@ namespace AgileObjects.AgileMapper.Members #else using System.Linq.Expressions; #endif + using AgileMapper.Extensions; + using AgileMapper.Extensions.Internal; using Caching; using Extensions; - using Extensions.Internal; using NetStandardPolyfills; using ReadableExpressions; using ReadableExpressions.Extensions; @@ -100,8 +101,6 @@ private ConfiguredSourceMember( public Type ElementType { get; } - public string GetFriendlyTypeName() => Type.GetFriendlyName(); - public bool IsEnumerable { get; } public bool IsSimple { get; } diff --git a/AgileMapper/Members/Dictionaries/DictionaryEntrySourceMember.cs b/AgileMapper/Members/Dictionaries/DictionaryEntrySourceMember.cs index dd2e92923..fea6b141d 100644 --- a/AgileMapper/Members/Dictionaries/DictionaryEntrySourceMember.cs +++ b/AgileMapper/Members/Dictionaries/DictionaryEntrySourceMember.cs @@ -6,7 +6,8 @@ namespace AgileObjects.AgileMapper.Members.Dictionaries #else using System.Linq.Expressions; #endif - using Extensions.Internal; + using AgileMapper.Extensions.Internal; + using Extensions; using ReadableExpressions.Extensions; internal class DictionaryEntrySourceMember : IQualifiedMember @@ -77,8 +78,6 @@ private DictionaryEntrySourceMember( public Type RootType => Parent.Type; - public string GetFriendlyTypeName() => Type.GetFriendlyName(); - public Type ElementType => _childMembers.Last().ElementType; public bool IsEnumerable { get; } diff --git a/AgileMapper/Members/Dictionaries/DictionaryMemberMapperDataExtensions.cs b/AgileMapper/Members/Dictionaries/DictionaryMemberMapperDataExtensions.cs index 2ff0bf2dd..a4ef028b1 100644 --- a/AgileMapper/Members/Dictionaries/DictionaryMemberMapperDataExtensions.cs +++ b/AgileMapper/Members/Dictionaries/DictionaryMemberMapperDataExtensions.cs @@ -2,14 +2,15 @@ namespace AgileObjects.AgileMapper.Members.Dictionaries { using System.Collections.Generic; using System.Linq; - using Extensions.Internal; - using NetStandardPolyfills; - using ReadableExpressions.Extensions; #if NET35 using Microsoft.Scripting.Ast; #else using System.Linq.Expressions; #endif + using AgileMapper.Extensions.Internal; + using Extensions; + using NetStandardPolyfills; + using ReadableExpressions.Extensions; internal static class DictionaryMemberMapperDataExtensions { diff --git a/AgileMapper/Members/Dictionaries/DictionarySourceMember.cs b/AgileMapper/Members/Dictionaries/DictionarySourceMember.cs index b190ee7bb..381545d16 100644 --- a/AgileMapper/Members/Dictionaries/DictionarySourceMember.cs +++ b/AgileMapper/Members/Dictionaries/DictionarySourceMember.cs @@ -6,10 +6,11 @@ namespace AgileObjects.AgileMapper.Members.Dictionaries #else using System.Linq.Expressions; #endif + using Extensions; using NetStandardPolyfills; using ReadableExpressions.Extensions; - internal class DictionarySourceMember : IQualifiedMember + internal class DictionarySourceMember : IQualifiedMemberWrapper { private readonly IQualifiedMember _wrappedSourceMember; private readonly QualifiedMember _matchedTargetMember; @@ -72,8 +73,6 @@ private DictionarySourceMember( public Type ElementType => ValueType; - public string GetFriendlyTypeName() => _wrappedSourceMember.GetFriendlyTypeName(); - public Type KeyType { get; } public Type ValueType { get; } @@ -92,6 +91,8 @@ private DictionarySourceMember( public string Name => _wrappedSourceMember.Name; + IQualifiedMember IQualifiedMemberWrapper.WrappedMember => _wrappedSourceMember; + public string GetPath() => _wrappedSourceMember.GetPath(); public IQualifiedMember GetElementMember() @@ -132,10 +133,7 @@ public Expression GetQualifiedAccess(Expression parentInstance) : EntryMember.GetQualifiedAccess(parentInstance); } - public IQualifiedMember SetContext(IQualifiedMemberContext context) - { - return this; - } + public IQualifiedMember SetContext(IQualifiedMemberContext context) => this; #region ExcludeFromCodeCoverage #if DEBUG diff --git a/AgileMapper/Members/Dictionaries/DictionaryTargetMember.cs b/AgileMapper/Members/Dictionaries/DictionaryTargetMember.cs index 68f494ec3..0b1132a02 100644 --- a/AgileMapper/Members/Dictionaries/DictionaryTargetMember.cs +++ b/AgileMapper/Members/Dictionaries/DictionaryTargetMember.cs @@ -6,16 +6,20 @@ namespace AgileObjects.AgileMapper.Members.Dictionaries using System.Linq; #if NET35 using Microsoft.Scripting.Ast; - using static Microsoft.Scripting.Ast.ExpressionType; #else using System.Linq.Expressions; - using static System.Linq.Expressions.ExpressionType; #endif + using AgileMapper.Extensions; + using AgileMapper.Extensions.Internal; using Extensions; - using Extensions.Internal; using NetStandardPolyfills; using ReadableExpressions.Extensions; using TypeConversion; +#if NET35 + using static Microsoft.Scripting.Ast.ExpressionType; +#else + using static System.Linq.Expressions.ExpressionType; +#endif internal class DictionaryTargetMember : QualifiedMember { @@ -300,35 +304,55 @@ private static bool TryGetMappingBody(Expression value, out Expression mapping) return false; } - var mappingExpressions = GetMappingExpressions(mappingBlock); + var mappingExpressions = GetMappingExpressions(mappingBlock, out var variables); if (mappingExpressions.HasOne() && (mappingExpressions[0].NodeType == Block)) { - IList mappingVariables = mappingBlock.Variables; - mappingBlock = (BlockExpression)mappingExpressions[0]; - mappingVariables = mappingVariables.Append(mappingBlock.Variables); - mapping = mappingBlock.Update(mappingVariables, mappingBlock.Expressions); + mapping = mappingBlock.Update(variables, mappingBlock.Expressions); return true; } - mapping = mappingBlock.Variables.Any() - ? Expression.Block(mappingBlock.Variables, mappingExpressions) + mapping = variables.Any() + ? Expression.Block(variables, mappingExpressions) : mappingExpressions.ToExpression(); return true; } - private static IList GetMappingExpressions(Expression mapping) + private static IList GetMappingExpressions( + Expression mapping, + out List variables) { - var expressions = new List(); + var expressions = default(List); + variables = new List(); while (mapping.NodeType == Block) { var mappingBlock = (BlockExpression)mapping; - expressions.AddRange(mappingBlock.Expressions.Take(mappingBlock.Expressions.Count - 1)); - mapping = mappingBlock.Result; + if (mappingBlock.Variables.Any()) + { + variables.AddRange(mappingBlock.Variables); + } + + var blockExpressions = mappingBlock.Expressions; + + if (mappingBlock.Result.NodeType is Block) + { + expressions ??= new List(); + expressions.AddRange(blockExpressions.Take(blockExpressions.Count - 1)); + mapping = mappingBlock.Result; + continue; + } + + if (expressions == null) + { + return blockExpressions; + } + + expressions.AddRange(blockExpressions); + return expressions; } return expressions; diff --git a/AgileMapper/Members/MemberExtensions/MemberExpressionExtensions.cs b/AgileMapper/Members/Extensions/MemberExpressionExtensions.cs similarity index 96% rename from AgileMapper/Members/MemberExtensions/MemberExpressionExtensions.cs rename to AgileMapper/Members/Extensions/MemberExpressionExtensions.cs index 10d137430..f508bad8c 100644 --- a/AgileMapper/Members/MemberExtensions/MemberExpressionExtensions.cs +++ b/AgileMapper/Members/Extensions/MemberExpressionExtensions.cs @@ -1,4 +1,4 @@ -namespace AgileObjects.AgileMapper.Members.MemberExtensions +namespace AgileObjects.AgileMapper.Members.Extensions { using System; #if NET35 diff --git a/AgileMapper/Members/MemberExtensionMethods.cs b/AgileMapper/Members/Extensions/MemberExtensionMethods.cs similarity index 96% rename from AgileMapper/Members/MemberExtensionMethods.cs rename to AgileMapper/Members/Extensions/MemberExtensionMethods.cs index 24a5d63f5..f7609716f 100644 --- a/AgileMapper/Members/MemberExtensionMethods.cs +++ b/AgileMapper/Members/Extensions/MemberExtensionMethods.cs @@ -1,4 +1,4 @@ -namespace AgileObjects.AgileMapper.Members +namespace AgileObjects.AgileMapper.Members.Extensions { using System; using System.Collections.Generic; @@ -7,15 +7,14 @@ using System.Linq; #if NET35 using Microsoft.Scripting.Ast; - using LinqExp = System.Linq.Expressions; #else using System.Linq.Expressions; #endif using System.Reflection; + using AgileMapper.Extensions; + using AgileMapper.Extensions.Internal; using Caching.Dictionaries; using Configuration; - using Extensions; - using Extensions.Internal; using NetStandardPolyfills; using ObjectPopulation; using ReadableExpressions; @@ -23,12 +22,24 @@ using static System.StringComparison; using static Constants; using static Member; +#if NET35 + using LinqExp = System.Linq.Expressions; +#endif internal static class MemberExtensionMethods { public static string GetFullName(this IEnumerable members) => members.Project(m => m.JoiningName).Join(string.Empty); + public static string GetTypeName(this IQualifiedMember member) + => member.GetNamingType().Name; + + public static string GetFriendlyTypeName(this IQualifiedMember member) + => member.GetNamingType().GetFriendlyName(); + + private static Type GetNamingType(this IQualifiedMember member) + => (member is IQualifiedMemberWrapper wrapper ? wrapper.WrappedMember : member).Type; + public static string GetFriendlySourcePath(this IQualifiedMember sourceMember, IMemberMapperData rootMapperData) => GetFriendlyMemberPath(sourceMember, rootMapperData.SourceMember); @@ -280,7 +291,7 @@ public static QualifiedMember ToSourceMemberOrNull( this Expression memberAccess, MapperContext mapperContext) { - return memberAccess.ToSourceMember(mapperContext, nt => { }); + return memberAccess.ToSourceMember(mapperContext, _ => { }); } public static QualifiedMember ToSourceMemberOrNull( @@ -289,7 +300,7 @@ public static QualifiedMember ToSourceMemberOrNull( out string failureReason) { var hasUnsupportedNodeType = false; - var sourceMember = memberAccess.ToSourceMember(mapperContext, nt => hasUnsupportedNodeType = true); + var sourceMember = memberAccess.ToSourceMember(mapperContext, _ => hasUnsupportedNodeType = true); if (hasUnsupportedNodeType) { @@ -323,7 +334,7 @@ public static QualifiedMember ToSourceMember( nonMemberAction ?? ThrowIfUnsupported, mapperContext); } - + #if NET35 public static QualifiedMember ToTargetMemberOrNull(this LinqExp.LambdaExpression memberAccess, MapperContext mapperContext) => memberAccess.ToDlrExpression().ToTargetMemberOrNull(mapperContext); @@ -342,7 +353,7 @@ public static QualifiedMember ToTargetMemberOrNull( out string failureReason) { var hasUnsupportedNodeType = false; - var targetMember = memberAccess.ToTargetMember(mapperContext, nt => hasUnsupportedNodeType = true); + var targetMember = memberAccess.ToTargetMember(mapperContext, _ => hasUnsupportedNodeType = true); if (hasUnsupportedNodeType) { diff --git a/AgileMapper/Members/MemberExtensions/NestedAccessChecksFactory.cs b/AgileMapper/Members/Extensions/NestedAccessChecksFactory.cs similarity index 99% rename from AgileMapper/Members/MemberExtensions/NestedAccessChecksFactory.cs rename to AgileMapper/Members/Extensions/NestedAccessChecksFactory.cs index 6248e0168..18b3fa715 100644 --- a/AgileMapper/Members/MemberExtensions/NestedAccessChecksFactory.cs +++ b/AgileMapper/Members/Extensions/NestedAccessChecksFactory.cs @@ -1,4 +1,4 @@ -namespace AgileObjects.AgileMapper.Members.MemberExtensions +namespace AgileObjects.AgileMapper.Members.Extensions { using System; using System.Collections.Generic; @@ -8,8 +8,8 @@ #else using System.Linq.Expressions; #endif - using Extensions; - using Extensions.Internal; + using AgileMapper.Extensions; + using AgileMapper.Extensions.Internal; using NetStandardPolyfills; using ReadableExpressions.Extensions; #if NET35 diff --git a/AgileMapper/Members/IMappingData.cs b/AgileMapper/Members/IMappingData.cs index bf2dade70..603bee32f 100644 --- a/AgileMapper/Members/IMappingData.cs +++ b/AgileMapper/Members/IMappingData.cs @@ -1,7 +1,5 @@ namespace AgileObjects.AgileMapper.Members { - using System; - /// /// Provides the data being used at a particular point during a mapping. /// @@ -29,17 +27,6 @@ public interface IMappingData /// The target object for the mapping context. TTarget GetTarget(); - /// - /// Gets the index of the current enumerable element being mapped in the mapping context - /// described by this , if applicable. - /// - /// - /// The index of the current enumerable element being mapped in the mapping context described - /// by this , otherwise null. - /// - [Obsolete("Use GetElementIndex() instead. This method will be removed in a future release.")] - int? GetEnumerableIndex(); - /// /// Gets the index of the current enumerable element being mapped in the mapping context /// described by this , if applicable. @@ -95,19 +82,12 @@ public interface IMappingData : IServiceProviderAccess /// TTarget Target { get; } - /// - /// Gets the index of the current enumerable element being mapped in the mapping context - /// described by this , if applicable. - /// - [Obsolete("Use ElementIndex instead. This property will be removed in a future release.")] - int? EnumerableIndex { get; } - /// /// Gets the index of the current enumerable element being mapped in the mapping context /// described by this , if applicable. /// int? ElementIndex { get; } - + /// /// Gets the key of the current Dictionary KeyValuePair being mapped in the mapping context /// described by this , if applicable. diff --git a/AgileMapper/Members/IMappingExceptionData.cs b/AgileMapper/Members/IMappingExceptionData.cs index 1eb81cfe3..e686351f3 100644 --- a/AgileMapper/Members/IMappingExceptionData.cs +++ b/AgileMapper/Members/IMappingExceptionData.cs @@ -20,13 +20,6 @@ public interface IMappingExceptionData : IServiceProviderAccessor /// object Target { get; } - /// - /// Gets the index of the current enumerable element being mapped when the mapping Exception - /// occurred, if applicable. - /// - [Obsolete("Use ElementIndex instead. This property will be removed in a future release.")] - int? EnumerableIndex { get; } - /// /// Gets the index of the current enumerable element being mapped when the mapping Exception /// occurred, if applicable. diff --git a/AgileMapper/Members/IQualifiedMember.cs b/AgileMapper/Members/IQualifiedMember.cs index 47a78c9c6..b5c101b66 100644 --- a/AgileMapper/Members/IQualifiedMember.cs +++ b/AgileMapper/Members/IQualifiedMember.cs @@ -17,8 +17,6 @@ internal interface IQualifiedMember Type ElementType { get; } - string GetFriendlyTypeName(); - bool IsEnumerable { get; } bool IsSimple { get; } diff --git a/AgileMapper/Members/IQualifiedMemberWrapper.cs b/AgileMapper/Members/IQualifiedMemberWrapper.cs new file mode 100644 index 000000000..aacb20e94 --- /dev/null +++ b/AgileMapper/Members/IQualifiedMemberWrapper.cs @@ -0,0 +1,7 @@ +namespace AgileObjects.AgileMapper.Members +{ + internal interface IQualifiedMemberWrapper : IQualifiedMember + { + IQualifiedMember WrappedMember { get; } + } +} \ No newline at end of file diff --git a/AgileMapper/Members/MappingInstanceData.cs b/AgileMapper/Members/MappingInstanceData.cs index abe5939d9..7ef64d180 100644 --- a/AgileMapper/Members/MappingInstanceData.cs +++ b/AgileMapper/Members/MappingInstanceData.cs @@ -42,8 +42,6 @@ protected MappingInstanceData( public TTarget Target { get; set; } - int? IMappingData.EnumerableIndex => ElementIndex; - public int? ElementIndex { get; } public object ElementKey { get; } @@ -68,8 +66,6 @@ T IMappingData.GetTarget() return default(T); } - int? IMappingData.GetEnumerableIndex() => GetElementIndex(); - public int? GetElementIndex() => ElementIndex ?? _parent?.GetElementIndex(); public object GetElementKey() => ElementKey ?? _parent?.GetElementKey(); diff --git a/AgileMapper/Members/Member.cs b/AgileMapper/Members/Member.cs index 8d6363ce8..53076ff06 100644 --- a/AgileMapper/Members/Member.cs +++ b/AgileMapper/Members/Member.cs @@ -7,9 +7,10 @@ namespace AgileObjects.AgileMapper.Members #else using System.Linq.Expressions; #endif + using AgileMapper.Extensions; + using AgileMapper.Extensions.Internal; using Dictionaries; using Extensions; - using Extensions.Internal; using NetStandardPolyfills; using ObjectPopulation; using ReadableExpressions.Extensions; diff --git a/AgileMapper/Members/MemberCache.cs b/AgileMapper/Members/MemberCache.cs index 837ab19ab..558a1f4ed 100644 --- a/AgileMapper/Members/MemberCache.cs +++ b/AgileMapper/Members/MemberCache.cs @@ -4,9 +4,9 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; + using AgileMapper.Extensions; + using AgileMapper.Extensions.Internal; using Caching; - using Extensions; - using Extensions.Internal; using NetStandardPolyfills; using ReadableExpressions.Extensions; using static System.StringComparer; diff --git a/AgileMapper/Members/MemberIdentifierSet.cs b/AgileMapper/Members/MemberIdentifierSet.cs index c67ebee0f..9bfc02e11 100644 --- a/AgileMapper/Members/MemberIdentifierSet.cs +++ b/AgileMapper/Members/MemberIdentifierSet.cs @@ -3,14 +3,15 @@ namespace AgileObjects.AgileMapper.Members using System; using System.Collections.Generic; using System.Linq; - using Configuration; - using NetStandardPolyfills; - using ReadableExpressions.Extensions; #if NET35 using Microsoft.Scripting.Ast; #else using System.Linq.Expressions; #endif + using Configuration; + using Extensions; + using NetStandardPolyfills; + using ReadableExpressions.Extensions; internal class MemberIdentifierSet { diff --git a/AgileMapper/Members/MemberMapperDataExtensions.cs b/AgileMapper/Members/MemberMapperDataExtensions.cs index d9a2fed37..00e281b93 100644 --- a/AgileMapper/Members/MemberMapperDataExtensions.cs +++ b/AgileMapper/Members/MemberMapperDataExtensions.cs @@ -10,14 +10,14 @@ namespace AgileObjects.AgileMapper.Members using System.Linq.Expressions; #endif using System.Reflection; + using AgileMapper.Extensions; + using AgileMapper.Extensions.Internal; using Configuration; using Configuration.DataSources; using Configuration.MemberIgnores.SourceValueFilters; using DataSources; using Dictionaries; using Extensions; - using Extensions.Internal; - using MemberExtensions; using NetStandardPolyfills; using ObjectPopulation; using ObjectPopulation.Enumerables.EnumerableExtensions; diff --git a/AgileMapper/Members/NamingSettings.cs b/AgileMapper/Members/NamingSettings.cs index d142ed6fd..4138558ac 100644 --- a/AgileMapper/Members/NamingSettings.cs +++ b/AgileMapper/Members/NamingSettings.cs @@ -3,10 +3,10 @@ using System; using System.Collections.Generic; using System.Linq; + using AgileMapper.Extensions; + using AgileMapper.Extensions.Internal; using Caching; using Configuration; - using Extensions; - using Extensions.Internal; internal class NamingSettings { diff --git a/AgileMapper/Members/Population/MemberPopulator.cs b/AgileMapper/Members/Population/MemberPopulator.cs index 47134673f..0e4001b26 100644 --- a/AgileMapper/Members/Population/MemberPopulator.cs +++ b/AgileMapper/Members/Population/MemberPopulator.cs @@ -5,8 +5,8 @@ namespace AgileObjects.AgileMapper.Members.Population #else using System.Linq.Expressions; #endif + using AgileMapper.Extensions.Internal; using DataSources; - using Extensions.Internal; internal class MemberPopulator : IMemberPopulator { diff --git a/AgileMapper/Members/Population/MemberPopulatorFactory.cs b/AgileMapper/Members/Population/MemberPopulatorFactory.cs index 5c9e308e2..d32e0aa1e 100644 --- a/AgileMapper/Members/Population/MemberPopulatorFactory.cs +++ b/AgileMapper/Members/Population/MemberPopulatorFactory.cs @@ -2,15 +2,15 @@ namespace AgileObjects.AgileMapper.Members.Population { using System; using System.Collections.Generic; + using AgileMapper.Extensions; + using AgileMapper.Extensions.Internal; using DataSources.Factories; - using Extensions; - using Extensions.Internal; using Members; using ObjectPopulation; internal class MemberPopulatorFactory { - public static readonly MemberPopulatorFactory Default = new MemberPopulatorFactory(mapperData => + public static readonly MemberPopulatorFactory Default = new(mapperData => GlobalContext.Instance .MemberCache .GetTargetMembers(mapperData.TargetType) diff --git a/AgileMapper/Members/Population/NullMemberPopulator.cs b/AgileMapper/Members/Population/NullMemberPopulator.cs index 4232926d5..b4360d82b 100644 --- a/AgileMapper/Members/Population/NullMemberPopulator.cs +++ b/AgileMapper/Members/Population/NullMemberPopulator.cs @@ -38,7 +38,7 @@ public static IMemberPopulator NoDataSources(MemberPopulationContext context) context.MemberMapperData.RegisterTargetMemberDataSources(noDataSources); - return CreateNullMemberPopulator(noDataSourcesMessage, context, (msg, md) => msg); + return CreateNullMemberPopulator(noDataSourcesMessage, context, (msg, _) => msg); } private static string GetNoDataSourcesMessage(QualifiedMember targetMember) @@ -63,7 +63,7 @@ private static IMemberPopulator CreateNullMemberPopulator( MemberPopulationContext context, Func descriptionFactory) { - if (context.MappingContext.IgnoreUnsuccessfulMemberPopulations) + if (!context.MappingContext.PlanSettings.CommentUnmappedMembers) { return null; } diff --git a/AgileMapper/Members/QualifiedMember.cs b/AgileMapper/Members/QualifiedMember.cs index 18fd2dbb2..c52b11f1a 100644 --- a/AgileMapper/Members/QualifiedMember.cs +++ b/AgileMapper/Members/QualifiedMember.cs @@ -9,16 +9,17 @@ namespace AgileObjects.AgileMapper.Members #else using System.Linq.Expressions; #endif + using AgileMapper.Extensions.Internal; using Caching; using Dictionaries; - using Extensions.Internal; + using Extensions; using NetStandardPolyfills; using ReadableExpressions.Extensions; internal class QualifiedMember : IQualifiedMember { - public static readonly QualifiedMember All = new QualifiedMember(default(Member), null); - public static readonly QualifiedMember None = new QualifiedMember(default(Member), null); + public static readonly QualifiedMember All = new(default(Member), null); + public static readonly QualifiedMember None = new(default(Member), null); private readonly MapperContext _mapperContext; private readonly QualifiedMember _parent; @@ -38,7 +39,7 @@ protected QualifiedMember(Member[] memberChain, QualifiedMember adaptedMember) foreach (var childMember in adaptedMember._childMemberCache.Values) { - _childMemberCache.GetOrAdd(childMember.LeafMember, m => childMember); + _childMemberCache.GetOrAdd(childMember.LeafMember, _ => childMember); } } @@ -155,8 +156,6 @@ public static QualifiedMember Create(Member[] memberChain, MapperContext mapperC public Type RootType => MemberChain[0].Type; - public string GetFriendlyTypeName() => Type.GetFriendlyName(); - public Type ElementType => LeafMember?.ElementType; public virtual Type GetElementType(Type sourceElementType) => ElementType; diff --git a/AgileMapper/Members/SourceMemberMatch.cs b/AgileMapper/Members/SourceMemberMatch.cs index bc462973a..ba76ed96f 100644 --- a/AgileMapper/Members/SourceMemberMatch.cs +++ b/AgileMapper/Members/SourceMemberMatch.cs @@ -5,12 +5,13 @@ #else using System.Linq.Expressions; #endif + using AgileMapper.Extensions.Internal; using DataSources; - using Extensions.Internal; + using Extensions; internal class SourceMemberMatch { - public static readonly SourceMemberMatch Null = new SourceMemberMatch(); + public static readonly SourceMemberMatch Null = new(); private SourceMemberMatch() { diff --git a/AgileMapper/Members/SourceMemberMatchContext.cs b/AgileMapper/Members/SourceMemberMatchContext.cs index a2bb6dc9b..1be112f75 100644 --- a/AgileMapper/Members/SourceMemberMatchContext.cs +++ b/AgileMapper/Members/SourceMemberMatchContext.cs @@ -6,9 +6,9 @@ #else using System.Linq.Expressions; #endif + using AgileMapper.Extensions.Internal; using Configuration; using Configuration.MemberIgnores; - using Extensions.Internal; using NetStandardPolyfills; internal class SourceMemberMatchContext diff --git a/AgileMapper/Members/SourceMemberMatcher.cs b/AgileMapper/Members/SourceMemberMatcher.cs index 8c4a61c02..a9991f286 100644 --- a/AgileMapper/Members/SourceMemberMatcher.cs +++ b/AgileMapper/Members/SourceMemberMatcher.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; - using Extensions; + using AgileMapper.Extensions; using TypeConversion; internal static class SourceMemberMatcher diff --git a/AgileMapper/Members/Sources/ElementMembersSource.cs b/AgileMapper/Members/Sources/ElementMembersSource.cs index bcd687a6a..e42f5e19d 100644 --- a/AgileMapper/Members/Sources/ElementMembersSource.cs +++ b/AgileMapper/Members/Sources/ElementMembersSource.cs @@ -1,5 +1,6 @@ namespace AgileObjects.AgileMapper.Members.Sources { + using Extensions; using ObjectPopulation; internal class ElementMembersSource : IMembersSource diff --git a/AgileMapper/ObjectPopulation/ComplexTypes/ShortCircuits/AlreadyMappedObjectShortCircuitFactory.cs b/AgileMapper/ObjectPopulation/ComplexTypes/ShortCircuits/AlreadyMappedObjectShortCircuitFactory.cs index 5c2df199f..cc8fe1827 100644 --- a/AgileMapper/ObjectPopulation/ComplexTypes/ShortCircuits/AlreadyMappedObjectShortCircuitFactory.cs +++ b/AgileMapper/ObjectPopulation/ComplexTypes/ShortCircuits/AlreadyMappedObjectShortCircuitFactory.cs @@ -5,7 +5,6 @@ namespace AgileObjects.AgileMapper.ObjectPopulation.ComplexTypes.ShortCircuits #else using System.Linq.Expressions; #endif - using Members; using NetStandardPolyfills; using ReadableExpressions.Extensions; diff --git a/AgileMapper/ObjectPopulation/ComplexTypes/TargetObjectResolutionFactory.cs b/AgileMapper/ObjectPopulation/ComplexTypes/TargetObjectResolutionFactory.cs index bd77a497e..53b752165 100644 --- a/AgileMapper/ObjectPopulation/ComplexTypes/TargetObjectResolutionFactory.cs +++ b/AgileMapper/ObjectPopulation/ComplexTypes/TargetObjectResolutionFactory.cs @@ -19,7 +19,7 @@ public static Expression GetObjectResolution( bool assignTargetObject = false) { return GetObjectResolution( - (md, mps) => construction, + (_, _) => construction, mappingData, null, false, @@ -75,8 +75,7 @@ public static Expression GetObjectResolution( } } - objectValue = AddExistingTargetCheckIfAppropriate(objectValue, mappingData); - + objectValue = AddExistingTargetCheckIfAppropriate(objectValue, mapperData); return objectValue; } @@ -118,17 +117,18 @@ private static bool UseNullFallbackValue( private static bool MemberPopulationsExist(IList populationsAndCallbacks) => populationsAndCallbacks.Any(population => population.NodeType != ExpressionType.Constant); - private static Expression AddExistingTargetCheckIfAppropriate(Expression value, IObjectMappingData mappingData) + private static Expression AddExistingTargetCheckIfAppropriate(Expression value, IMemberMapperData mapperData) { if ((value.NodeType == ExpressionType.Default) || - mappingData.MapperData.RuleSet.Settings.UseSingleRootMappingExpression || - mappingData.MapperData.TargetMemberIsUserStruct() || - mappingData.MapperData.TargetIsDefinitelyUnpopulated()) + mapperData.RuleSet.Settings.UseSingleRootMappingExpression || + !mapperData.TargetMember.IsReadable || + mapperData.TargetMemberIsUserStruct() || + mapperData.TargetIsDefinitelyUnpopulated()) { return value; } - return Expression.Coalesce(mappingData.MapperData.TargetObject, value); + return Expression.Coalesce(mapperData.TargetObject, value); } } } \ No newline at end of file diff --git a/AgileMapper/ObjectPopulation/DerivedSourceTypeCheck.cs b/AgileMapper/ObjectPopulation/DerivedSourceTypeCheck.cs index a8d4734b4..ea9d1873c 100644 --- a/AgileMapper/ObjectPopulation/DerivedSourceTypeCheck.cs +++ b/AgileMapper/ObjectPopulation/DerivedSourceTypeCheck.cs @@ -8,6 +8,7 @@ namespace AgileObjects.AgileMapper.ObjectPopulation #endif using Extensions.Internal; using Members; + using ReadableExpressions.Extensions; internal class DerivedSourceTypeCheck { diff --git a/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs b/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs index d1e2021b1..cf15e54be 100644 --- a/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs +++ b/AgileMapper/ObjectPopulation/DictionaryMappingExpressionFactory.cs @@ -475,9 +475,7 @@ private Expression GetDictionaryPopulation(IObjectMappingData mappingData) return memberPopulations[0]; } - var memberPopulationBlock = Expression.Block(memberPopulations); - - return memberPopulationBlock; + return Expression.Block(memberPopulations); } private static Expression GetEnumerableToDictionaryMapping(IObjectMappingData mappingData) diff --git a/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/DictionaryPopulationBuilder.cs b/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/DictionaryPopulationBuilder.cs index 10ec81a27..0ad31628a 100644 --- a/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/DictionaryPopulationBuilder.cs +++ b/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/DictionaryPopulationBuilder.cs @@ -14,6 +14,7 @@ using Looping; using Members; using Members.Dictionaries; + using Members.Extensions; using Members.Population; using TypeConversion; diff --git a/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/Looping/SourceElementsDictionaryPopulationLoopData.cs b/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/Looping/SourceElementsDictionaryPopulationLoopData.cs index deb7f5483..50a2f872a 100644 --- a/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/Looping/SourceElementsDictionaryPopulationLoopData.cs +++ b/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/Looping/SourceElementsDictionaryPopulationLoopData.cs @@ -12,6 +12,7 @@ namespace AgileObjects.AgileMapper.ObjectPopulation.Enumerables.Dictionaries.Loo using Extensions; using Extensions.Internal; using NetStandardPolyfills; + using static Constants; internal class SourceElementsDictionaryPopulationLoopData : IPopulationLoopData { @@ -186,8 +187,8 @@ private Expression GetElementMappingBlock(Expression elementMapping) public Expression Adapt(LoopExpression loop) { loop = loop - .InsertAssignment(Constants.BeforeLoopExitCheck, _dictionaryVariables.Key, _targetElementKey) - .InsertAssignment(Constants.BeforeLoopExitCheck, _targetElementKey, _targetMemberKey); + .InsertAssignment(BeforeLoopExitCheck, _dictionaryVariables.Key, _targetElementKey) + .InsertAssignment(BeforeLoopExitCheck, _targetElementKey, _targetMemberKey); var loopBody = (BlockExpression)loop.Body; diff --git a/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/SourceAdapters/SourceObjectDictionaryAdapter.cs b/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/SourceAdapters/SourceObjectDictionaryAdapter.cs index 820af2d92..43d7dce18 100644 --- a/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/SourceAdapters/SourceObjectDictionaryAdapter.cs +++ b/AgileMapper/ObjectPopulation/Enumerables/Dictionaries/SourceAdapters/SourceObjectDictionaryAdapter.cs @@ -11,7 +11,6 @@ namespace AgileObjects.AgileMapper.ObjectPopulation.Enumerables.Dictionaries.Sou using Enumerables.SourceAdapters; using Extensions.Internal; using Looping; - using Members; using Members.Dictionaries; using NetStandardPolyfills; diff --git a/AgileMapper/ObjectPopulation/Enumerables/EnumerableMappingExpressionFactory.cs b/AgileMapper/ObjectPopulation/Enumerables/EnumerableMappingExpressionFactory.cs index b21370b8c..ae2b49e7f 100644 --- a/AgileMapper/ObjectPopulation/Enumerables/EnumerableMappingExpressionFactory.cs +++ b/AgileMapper/ObjectPopulation/Enumerables/EnumerableMappingExpressionFactory.cs @@ -7,6 +7,7 @@ namespace AgileObjects.AgileMapper.ObjectPopulation.Enumerables #endif using Extensions.Internal; using Members; + using Members.Extensions; using TypeConversion; internal class EnumerableMappingExpressionFactory : MappingExpressionFactoryBase diff --git a/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationBuilder.cs b/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationBuilder.cs index 1d0d60a80..7fdd5ddf0 100644 --- a/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationBuilder.cs +++ b/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationBuilder.cs @@ -48,7 +48,6 @@ public EnumerablePopulationBuilder(ObjectMapperData mapperData) Context = new EnumerablePopulationContext(mapperData); _sourceItemsSelector = new SourceItemsSelector(this); _sourceElementParameter = Context.SourceElementType.GetOrCreateParameter(); - TargetTypeHelper = new EnumerableTypeHelper(mapperData.TargetMember); _sourceAdapter = SourceEnumerableAdapterFactory.GetAdapterFor(this); _populationExpressions = new List(); @@ -250,7 +249,7 @@ private static LambdaExpression GetTargetElementIdLambda(ParameterExpression tar public bool TargetElementsAreSimple => Context.TargetElementsAreSimple; - public EnumerableTypeHelper SourceTypeHelper { get; private set; } + public EnumerableTypeHelper SourceTypeHelper => Context.SourceTypeHelper; public Expression SourceValue { get; private set; } @@ -258,18 +257,12 @@ private static LambdaExpression GetTargetElementIdLambda(ParameterExpression tar public Expression GetSourceIndexAccess() => SourceValue.GetIndexAccess(Counter); - public EnumerableTypeHelper TargetTypeHelper { get; } + public EnumerableTypeHelper TargetTypeHelper => Context.TargetTypeHelper; public ParameterExpression TargetVariable { get => _targetVariable; - set - { - if (_targetVariable == null) - { - _targetVariable = value; - } - } + set => _targetVariable ??= value; } public void AssignSourceVariableToSourceObject() @@ -278,7 +271,7 @@ public void AssignSourceVariableToSourceObject() if (SourceVariableAlreadyAssignedTo(SourceValue)) { - CreateSourceTypeHelper(SourceValue); + Context.CreateSourceTypeHelper(SourceValue); return; } @@ -300,24 +293,17 @@ private bool SourceVariableAlreadyAssignedTo(Expression value) } public void AssignSourceVariableTo(Func sourceItemsSelection) - => AssignSourceVariableTo(sourceItemsSelection.Invoke(_sourceItemsSelector).GetResult()); + => AssignSourceVariableTo(sourceItemsSelection.Invoke(_sourceItemsSelector)); private void AssignSourceVariableTo(Expression sourceValue) { - CreateSourceTypeHelper(sourceValue); + Context.CreateSourceTypeHelper(sourceValue); SourceValue = _sourceVariable = Context.GetSourceParameterFor(sourceValue.Type); _populationExpressions.Add(_sourceVariable.AssignTo(sourceValue)); } - private void CreateSourceTypeHelper(Expression sourceValue) - { - SourceTypeHelper = new EnumerableTypeHelper( - sourceValue.Type, - Context.ElementTypesAreTheSame ? Context.TargetElementType : sourceValue.Type.GetEnumerableElementType()); - } - #region Target Variable Population public void PopulateTargetVariableFromSourceObjectOnly(IObjectMappingData enumerableMappingData = null) @@ -327,7 +313,7 @@ private Expression GetSourceOnlyReturnValue(IObjectMappingData enumerableMapping { var convertedSourceItems = _sourceItemsSelector .SourceItemsProjectedToTargetType(enumerableMappingData) - .GetResult(); + .ToTargetType(); var returnValue = ConvertForReturnValue(convertedSourceItems); @@ -573,7 +559,7 @@ private bool InsertSourceObjectElementNullCheck(IPopulationLoopData loopData, ou } public Expression GetElementConversion( - Expression sourceElement, + Expression sourceElement, IObjectMappingData enumerableMappingData) { if (TargetElementsAreSimple) @@ -711,8 +697,11 @@ public void CreateCollectionData() public void MapIntersection(IObjectMappingData enumerableMappingData) { - var sourceElementParameter = Context.GetSourceParameterFor(Context.SourceElementType); - var targetElementParameter = Context.GetTargetParameterFor(Context.TargetElementType); + var sourceElementParameter = Context.GetSourceParameterFor(Context.SourceElementType, prefix: "existing"); + var targetElementParameter = Context.GetTargetParameterFor(Context.TargetElementType, prefix: "existing"); + + var defaultLoopCounter = _counterVariable; + _counterVariable = Parameters.Create("idx"); var forEachActionType = Expression.GetActionType(Context.SourceElementType, Context.TargetElementType, typeof(int)); var forEachAction = GetElementMapping(sourceElementParameter, targetElementParameter, enumerableMappingData); @@ -722,7 +711,9 @@ public void MapIntersection(IObjectMappingData enumerableMappingData) forEachAction, sourceElementParameter, targetElementParameter, - Counter); + _counterVariable); + + _counterVariable = defaultLoopCounter; var forEachCall = Expression.Call( _forEachTupleMethod.MakeGenericMethod(Context.ElementTypes), @@ -803,6 +794,9 @@ internal SourceItemsSelector(EnumerablePopulationBuilder builder) _builder = builder; } + public static implicit operator Expression(SourceItemsSelector selector) + => selector._result; + public SourceItemsSelector SourceItemsProjectedToTargetType( IObjectMappingData enumerableMappingData = null) { @@ -843,7 +837,7 @@ public SourceItemsSelector CollectionDataNewSourceItems() return this; } - public Expression GetResult() + public Expression ToTargetType() { if (_result.NodeType == ExpressionType.MemberAccess) { diff --git a/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationContext.cs b/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationContext.cs index c7e72bca8..60561ea86 100644 --- a/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationContext.cs +++ b/AgileMapper/ObjectPopulation/Enumerables/EnumerablePopulationContext.cs @@ -10,12 +10,16 @@ using Extensions.Internal; using Members; using NetStandardPolyfills; + using ReadableExpressions.Extensions; internal class EnumerablePopulationContext { + private Type _mappingSourceElementType; + public EnumerablePopulationContext(IQualifiedMemberContext context) { - SourceElementType = context.SourceMember.ElementType; + _mappingSourceElementType = SourceElementType = context.SourceMember.ElementType; + TargetTypeHelper = new EnumerableTypeHelper(context.TargetMember); if (SourceElementType == null) { @@ -34,25 +38,58 @@ public EnumerablePopulationContext(IQualifiedMemberContext context) public Type[] ElementTypes { get; } + /// + /// Gets a value indicating whether the mapping is being performed between collections with + /// the same element Types. + /// public bool ElementTypesAreTheSame { get; } public bool ElementTypesAreAssignable => SourceElementType.IsAssignableTo(TargetElementType); public bool TargetElementsAreSimple { get; } - public ParameterExpression GetSourceParameterFor(Type type) => GetParameterFor(type, "source"); + public EnumerableTypeHelper SourceTypeHelper { get; private set; } + + public void CreateSourceTypeHelper(Expression sourceValue) + { + _mappingSourceElementType = ElementTypesAreTheSame + ? TargetElementType + : sourceValue.Type.GetEnumerableElementType(); + + SourceTypeHelper = new EnumerableTypeHelper(sourceValue.Type, _mappingSourceElementType); + } + + public EnumerableTypeHelper TargetTypeHelper { get; } - public ParameterExpression GetTargetParameterFor(Type type) => GetParameterFor(type, "target"); + public ParameterExpression GetSourceParameterFor(Type type, string prefix = null) + => GetParameterFor(type, prefix, "source"); - private ParameterExpression GetParameterFor(Type type, string sameTypesPrefix) + public ParameterExpression GetTargetParameterFor(Type type, string prefix = null) + => GetParameterFor(type, prefix, "target"); + + private ParameterExpression GetParameterFor( + Type type, + string prefix, + string sameTypesPrefix) { - var parameterName = ElementTypesAreTheSame - ? sameTypesPrefix + type.GetVariableNameInPascalCase() - : type.GetVariableNameInCamelCase(); + string parameterName; + + if (_mappingSourceElementType == TargetElementType) + { + parameterName = prefix != null + ? prefix + sameTypesPrefix.ToPascalCase() + : sameTypesPrefix; - var parameter = Expression.Parameter(type, parameterName); + parameterName += type.GetVariableNameInPascalCase(); + } + else + { + parameterName = prefix != null + ? prefix + type.GetVariableNameInPascalCase() + : type.GetVariableNameInCamelCase(); + } - return parameter; + return Parameters.Create(type, parameterName); } } } \ No newline at end of file diff --git a/AgileMapper/ObjectPopulation/Enumerables/EnumerableTypeHelper.cs b/AgileMapper/ObjectPopulation/Enumerables/EnumerableTypeHelper.cs index 43fa84730..61f68ab54 100644 --- a/AgileMapper/ObjectPopulation/Enumerables/EnumerableTypeHelper.cs +++ b/AgileMapper/ObjectPopulation/Enumerables/EnumerableTypeHelper.cs @@ -125,7 +125,7 @@ private bool IsReadOnlyCollectionInterface() private Type SetInterfaceType => GetEnumerableType(ref _setInterfaceType, typeof(ISet<>)); #endif private Type GetEnumerableType(ref Type typeField, Type openGenericEnumerableType) - => typeField ?? (typeField = openGenericEnumerableType.MakeGenericType(ElementType)); + => typeField ??= openGenericEnumerableType.MakeGenericType(ElementType); public Type WrapperType => typeof(ReadOnlyCollectionWrapper<>).MakeGenericType(ElementType); @@ -198,7 +198,7 @@ private static bool ValueIsNotEnumerableInterface(Expression instance) => instance.Type != typeof(IEnumerable<>).MakeGenericType(instance.Type.GetEnumerableElementType()); public Expression GetCountFor(Expression instance, Type countType = null) - => instance.GetCount(countType, exp => CollectionInterfaceType); + => instance.GetCount(countType, _ => CollectionInterfaceType); public Expression GetNonZeroCountCheck(Expression enumerableAccess) { diff --git a/AgileMapper/ObjectPopulation/Enumerables/Looping/IndexedSourcePopulationLoopData.cs b/AgileMapper/ObjectPopulation/Enumerables/Looping/IndexedSourcePopulationLoopData.cs index ac6ddd1a3..754f6c227 100644 --- a/AgileMapper/ObjectPopulation/Enumerables/Looping/IndexedSourcePopulationLoopData.cs +++ b/AgileMapper/ObjectPopulation/Enumerables/Looping/IndexedSourcePopulationLoopData.cs @@ -6,6 +6,7 @@ namespace AgileObjects.AgileMapper.ObjectPopulation.Enumerables.Looping using System.Linq.Expressions; #endif using Extensions.Internal; + using static Constants; internal class IndexedSourcePopulationLoopData : IPopulationLoopData { @@ -50,10 +51,10 @@ public Expression Adapt(LoopExpression loop) return loop; } - return loop.InsertAssignment( - Constants.AfterLoopExitCheck, - (ParameterExpression)_sourceElement, - _indexedSourceAccess); + var sourceVariable = (ParameterExpression)_sourceElement; + + return loop + .InsertAssignment(AfterLoopExitCheck, sourceVariable, _indexedSourceAccess); } } } \ No newline at end of file diff --git a/AgileMapper/ObjectPopulation/IObjectMapperFunc.cs b/AgileMapper/ObjectPopulation/IObjectMapperFunc.cs index 6044fe97b..3ad8de250 100644 --- a/AgileMapper/ObjectPopulation/IObjectMapperFunc.cs +++ b/AgileMapper/ObjectPopulation/IObjectMapperFunc.cs @@ -6,10 +6,13 @@ namespace AgileObjects.AgileMapper.ObjectPopulation using System.Linq.Expressions; #endif - internal interface IObjectMapperFunc + internal interface IObjectMapperFuncBase { - Expression Mapping { get; } - object Map(IObjectMappingData mappingData); } + + internal interface IObjectMapperFunc : IObjectMapperFuncBase + { + Expression Mapping { get; } + } } \ No newline at end of file diff --git a/AgileMapper/ObjectPopulation/IObjectMappingData.cs b/AgileMapper/ObjectPopulation/IObjectMappingData.cs index 3389e251f..732d35766 100644 --- a/AgileMapper/ObjectPopulation/IObjectMappingData.cs +++ b/AgileMapper/ObjectPopulation/IObjectMappingData.cs @@ -101,7 +101,7 @@ TDeclaredTarget Map( /// applicable. /// /// - /// The key of the current Dicionary KeyValuePair being mapped in the mapping context described + /// The key of the current Dictionary KeyValuePair being mapped in the mapping context described /// by this , if applicable. /// /// The element mapping result. diff --git a/AgileMapper/ObjectPopulation/IObjectMappingDataFactoryBridge.cs b/AgileMapper/ObjectPopulation/IUntypedObjectMappingDataFactory.cs similarity index 98% rename from AgileMapper/ObjectPopulation/IObjectMappingDataFactoryBridge.cs rename to AgileMapper/ObjectPopulation/IUntypedObjectMappingDataFactory.cs index d7b00c807..49553e452 100644 --- a/AgileMapper/ObjectPopulation/IObjectMappingDataFactoryBridge.cs +++ b/AgileMapper/ObjectPopulation/IUntypedObjectMappingDataFactory.cs @@ -4,7 +4,7 @@ namespace AgileObjects.AgileMapper.ObjectPopulation /// Provides bridge methods enabling creation of typed /// instances in partial trust scenarios. This interface is intended for internal use only. /// - public interface IObjectMappingDataFactoryBridge + public interface IUntypedObjectMappingDataFactory { /// /// Creates a child instance. diff --git a/AgileMapper/ObjectPopulation/MappingCreationContext.cs b/AgileMapper/ObjectPopulation/MappingCreationContext.cs index 1a785e84b..3265ab716 100644 --- a/AgileMapper/ObjectPopulation/MappingCreationContext.cs +++ b/AgileMapper/ObjectPopulation/MappingCreationContext.cs @@ -1,6 +1,7 @@ namespace AgileObjects.AgileMapper.ObjectPopulation { using System.Collections.Generic; + using System.Linq; #if NET35 using Microsoft.Scripting.Ast; #else @@ -79,9 +80,13 @@ public IList GetMemberMappingExpressions() return _memberMappingExpressions ?? Enumerable.EmptyArray; } - return _memberMappingExpressions = MappingExpressions.GetMemberMappingExpressions(); + return _memberMappingExpressions = + EnumerateMappingExpressions(includeCallbacks: true).ToList(); } + public IEnumerable EnumerateMappingExpressions(bool includeCallbacks) + => MappingExpressions.EnumerateMappingExpressions(includeCallbacks); + public MappingCreationContext WithToTargetDataSource(IDataSource dataSource) { var newSourceMappingData = MappingData.WithToTargetSource(dataSource.SourceMember); diff --git a/AgileMapper/ObjectPopulation/MappingDataFactory.cs b/AgileMapper/ObjectPopulation/MappingDataFactory.cs index b940fcfef..a211135cb 100644 --- a/AgileMapper/ObjectPopulation/MappingDataFactory.cs +++ b/AgileMapper/ObjectPopulation/MappingDataFactory.cs @@ -6,18 +6,36 @@ namespace AgileObjects.AgileMapper.ObjectPopulation using MapperKeys; using NetStandardPolyfills; - internal static class MappingDataFactory + /// + /// Factory class to create instances. This + /// class is used internally by mapping functions. + /// + public static class MappingDataFactory { private static MethodInfo _forChildMethod; private static MethodInfo _forElementMethod; - public static MethodInfo ForChildMethod => - _forChildMethod ?? (_forChildMethod = typeof(MappingDataFactory).GetPublicStaticMethod(nameof(ForChild))); - - public static MethodInfo ForElementMethod - => _forElementMethod ?? (_forElementMethod = typeof(MappingDataFactory).GetPublicStaticMethod(nameof(ForElement))); - - public static ObjectMappingData ForChild( + internal static MethodInfo ForChildMethod => + _forChildMethod ??= typeof(MappingDataFactory).GetPublicStaticMethod(nameof(ForChild)); + + internal static MethodInfo ForElementMethod + => _forElementMethod ??= typeof(MappingDataFactory).GetPublicStaticMethod(nameof(ForElement)); + + /// + /// Creates an instance for the given data, + /// for the mapping of a runtime-typed child member. + /// + /// The declared type of the source object. + /// The declared type of the target object. + /// The child source object. + /// The child target object. + /// The index of the current enumerable element being mapped, if applicable. + /// The current Dictionary KeyValuePair being mapped, if applicable. + /// The name of the target member being mapped. + /// The index of the source value being used. + /// The describing the parent mapping context. + /// An instance for the given data. + public static IObjectMappingData ForChild( TSource source, TTarget target, int? elementIndex, @@ -50,7 +68,19 @@ public static ObjectMappingData ForChild( return mappingData; } - public static ObjectMappingData ForElement( + /// + /// Creates an instance for the given data, + /// for the mapping of a runtime-typed collection element. + /// + /// The declared type of the source element. + /// The declared type of the target element. + /// The source element object. + /// The target element object. + /// The index of the current enumerable element being mapped, if applicable. + /// The current Dictionary KeyValuePair being mapped, if applicable. + /// The describing the parent mapping context. + /// An instance for the given data. + public static IObjectMappingData ForElement( TSourceElement sourceElement, TTargetElement targetElement, int elementIndex, diff --git a/AgileMapper/ObjectPopulation/MappingExpressionFactoryBase.cs b/AgileMapper/ObjectPopulation/MappingExpressionFactoryBase.cs index adf18a1b8..7b3106705 100644 --- a/AgileMapper/ObjectPopulation/MappingExpressionFactoryBase.cs +++ b/AgileMapper/ObjectPopulation/MappingExpressionFactoryBase.cs @@ -3,25 +3,25 @@ namespace AgileObjects.AgileMapper.ObjectPopulation using System; using System.Collections.Generic; using System.Linq; - using ComplexTypes.ShortCircuits; - using DataSources; #if NET35 using Microsoft.Scripting.Ast; #else using System.Linq.Expressions; #endif + using ComplexTypes.ShortCircuits; + using DataSources; using Enumerables.EnumerableExtensions; using Extensions; using Extensions.Internal; using Members; - using Members.MemberExtensions; + using Members.Extensions; using NetStandardPolyfills; - using ReadableExpressions; #if NET35 using static Microsoft.Scripting.Ast.ExpressionType; #else using static System.Linq.Expressions.ExpressionType; #endif + using static ReadableExpressions.ReadableExpression; internal abstract class MappingExpressionFactoryBase { @@ -31,9 +31,11 @@ public Expression Create(IObjectMappingData mappingData) if (TargetCannotBeMapped(mappingData, out var reason)) { - return Expression.Block( - ReadableExpression.Comment(reason), - GetNullMappingFallbackValue(mapperData)); + var fallbackValue = GetNullMappingFallbackValue(mapperData); + + return mappingData.MappingContext.PlanSettings.CommentUnmappableMembers + ? Expression.Block(Comment(reason), fallbackValue) + : fallbackValue; } var context = new MappingCreationContext(mappingData); @@ -404,25 +406,31 @@ private Expression GetMappingBlock(MappingCreationContext context) return firstExpression; } - Expression returnExpression; + if (TryAdjustForUnusedLocalVariableIfApplicable( + context, + out var localVariableUnused, + out var returnExpression)) + { + return returnExpression; + } + + var mapperData = context.MapperData; + returnExpression = GetExpressionToReturn(context); - if (firstExpression.NodeType != Block) + if (localVariableUnused && (returnExpression == mapperData.LocalVariable) && + context.EnumerateMappingExpressions(includeCallbacks: false).Any()) { - if (TryAdjustForUnusedLocalVariableIfApplicable(context, out returnExpression)) - { - return returnExpression; - } + mappingExpressions.Add(Constants.EmptyExpression); } - else if (TryAdjustForUnusedLocalVariableIfApplicable(context, out returnExpression)) + else { - return returnExpression; + mappingExpressions.Add(mapperData.GetReturnLabel(returnExpression)); + localVariableUnused = !mapperData.Context.UseLocalVariable; } - mappingExpressions.Add(context.MapperData.GetReturnLabel(GetExpressionToReturn(context))); - - var mappingBlock = context.MapperData.Context.UseLocalVariable - ? Expression.Block(new[] { context.MapperData.LocalVariable }, mappingExpressions) - : mappingExpressions.ToExpression(); + var mappingBlock = localVariableUnused + ? mappingExpressions.ToExpression() + : Expression.Block(new[] { mapperData.LocalVariable }, mappingExpressions); return mappingBlock; } @@ -443,24 +451,37 @@ private static void AdjustForSingleExpressionBlockIfApplicable(MappingCreationCo } } - private static bool TryAdjustForUnusedLocalVariableIfApplicable(MappingCreationContext context, out Expression returnExpression) + private static bool TryAdjustForUnusedLocalVariableIfApplicable( + MappingCreationContext context, + out bool localVariableUnused, + out Expression returnExpression) { - if (!context.MapperData.Context.UseLocalVariable) + var mapperData = context.MapperData; + + if (!mapperData.RuleSet.Settings.UseSingleRootMappingExpression && ( + !mapperData.Context.UseLocalVariable || + mapperData.ReturnLabelUsed || + context.ToTargetDataSources.Any())) { + localVariableUnused = false; returnExpression = null; return false; } var mappingExpressions = context.MappingExpressions; - if (!mappingExpressions.TryGetVariableAssignment(out var localVariableAssignment)) + if (!mappingExpressions.TryGetAssignment( + mapperData.LocalVariable, + out var localVariableAssignment)) { + localVariableUnused = true; returnExpression = null; return false; } - if ((localVariableAssignment.Left.NodeType != Parameter) || - (localVariableAssignment != mappingExpressions.Last())) + localVariableUnused = false; + + if (localVariableAssignment != mappingExpressions.Last()) { returnExpression = null; return false; @@ -470,7 +491,7 @@ private static bool TryAdjustForUnusedLocalVariableIfApplicable(MappingCreationC returnExpression = (assignedValue.NodeType == Invoke) ? Expression.Block( - new[] { (ParameterExpression)localVariableAssignment.Left }, + new[] { mapperData.LocalVariable }, GetExpressionToReturn(localVariableAssignment, context)) : GetExpressionToReturn(assignedValue, context); @@ -479,7 +500,7 @@ private static bool TryAdjustForUnusedLocalVariableIfApplicable(MappingCreationC return true; } - mappingExpressions[mappingExpressions.Count - 1] = context.MapperData.GetReturnLabel(returnExpression); + mappingExpressions[mappingExpressions.Count - 1] = mapperData.GetReturnLabel(returnExpression); returnExpression = Expression.Block(mappingExpressions); return true; } diff --git a/AgileMapper/ObjectPopulation/MappingFactory.cs b/AgileMapper/ObjectPopulation/MappingFactory.cs index 5c94cd8b2..d1a773acd 100644 --- a/AgileMapper/ObjectPopulation/MappingFactory.cs +++ b/AgileMapper/ObjectPopulation/MappingFactory.cs @@ -8,7 +8,7 @@ using Caching.Dictionaries; using Extensions.Internal; using Members; - using Members.MemberExtensions; + using Members.Extensions; using NetStandardPolyfills; internal static class MappingFactory diff --git a/AgileMapper/ObjectPopulation/MemberMapperDataBase.cs b/AgileMapper/ObjectPopulation/MemberMapperDataBase.cs index 561255bf3..5bdf3d445 100644 --- a/AgileMapper/ObjectPopulation/MemberMapperDataBase.cs +++ b/AgileMapper/ObjectPopulation/MemberMapperDataBase.cs @@ -35,15 +35,9 @@ protected MemberMapperDataBase( TargetObject = GetMappingDataProperty(Member.RootTargetMemberName); } - public ObjectMapperData Parent { get; } - - public ParameterExpression MappingDataObject { get; } - - public Expression SourceObject { get; set; } + #region Setup - public Expression TargetObject { get; set; } - - protected ParameterExpression CreateMappingDataObject() + private ParameterExpression CreateMappingDataObject() { var mdType = typeof(IObjectMappingData<,>).MakeGenericType(SourceType, TargetType); @@ -70,7 +64,27 @@ protected ParameterExpression CreateMappingDataObject() return Expression.Parameter(mdType, mappingDataVariableName); } - protected Type MappingDataType { get; } + private Expression GetMappingDataProperty(Type mappingDataType, string propertyName) + { + var property = mappingDataType.GetPublicInstanceProperty(propertyName); + + return Expression.Property(MappingDataObject, property); + } + + protected Expression GetMappingDataProperty(string propertyName) + => Expression.Property(MappingDataObject, propertyName); + + #endregion + + public ObjectMapperData Parent { get; } + + public ParameterExpression MappingDataObject { get; } + + public Expression SourceObject { get; set; } + + public Expression TargetObject { get; set; } + + private Type MappingDataType { get; } protected Expression GetElementIndexAccess() => GetMappingDataProperty(MappingDataType, "ElementIndex"); @@ -80,15 +94,5 @@ protected Expression GetElementKeyAccess() protected Expression GetParentObjectAccess() => GetMappingDataProperty(nameof(Parent)); - - protected Expression GetMappingDataProperty(Type mappingDataType, string propertyName) - { - var property = mappingDataType.GetPublicInstanceProperty(propertyName); - - return Expression.Property(MappingDataObject, property); - } - - protected Expression GetMappingDataProperty(string propertyName) - => Expression.Property(MappingDataObject, propertyName); } } \ No newline at end of file diff --git a/AgileMapper/ObjectPopulation/ObjectMapper.cs b/AgileMapper/ObjectPopulation/ObjectMapper.cs index 035f7f36d..d2bdd8c07 100644 --- a/AgileMapper/ObjectPopulation/ObjectMapper.cs +++ b/AgileMapper/ObjectPopulation/ObjectMapper.cs @@ -16,9 +16,11 @@ namespace AgileObjects.AgileMapper.ObjectPopulation internal class ObjectMapper : IObjectMapper { private readonly ObjectMapperKeyBase _mapperKey; - private readonly MapperFunc _mapperFunc; + private MapperFunc _mapperFunc; + private readonly object _lazyMapperFuncSync; private readonly ICache _subMappersByKey; private readonly ICache _repeatedMappingFuncsByKey; + private bool _mapperFuncCompiled; private Action _resetCallback; public ObjectMapper(Expression mapping, IObjectMappingData mappingData) @@ -31,7 +33,15 @@ public ObjectMapper(Expression mapping, IObjectMappingData mappingData) if (mapperDataContext.Compile) { - _mapperFunc = GetMappingLambda().Compile(); + if (mappingData.MappingContext.PlanSettings.LazyCompile) + { + _mapperFunc = LazyCompileMapperFunc; + _lazyMapperFuncSync = new object(); + } + else + { + _mapperFunc = CompileMapperFunc(); + } } else if (mapperDataContext.NeedsRuntimeTypedMapping) { @@ -54,6 +64,25 @@ public ObjectMapper(Expression mapping, IObjectMappingData mappingData) #region Setup + private TTarget LazyCompileMapperFunc(ObjectMappingData mappingData) + { + lock (_lazyMapperFuncSync) + { + if (_mapperFuncCompiled) + { + return Map(mappingData); + } + + _mapperFunc = CompileMapperFunc(); + _mapperFuncCompiled = true; + } + + return Map(mappingData); + } + + private MapperFunc CompileMapperFunc() + => GetMappingLambda().Compile(); + public void CacheRepeatedMappingFuncs() { // Using a for loop here because creation of a repeated mapping func can @@ -87,7 +116,7 @@ public void CacheRepeatedMappingFuncs() var mapperFunc = mapperFuncCreator.Invoke( mapperKey.MappingData, - mapperKey.MappingData.MappingContext.LazyLoadRepeatMappingFuncs); + mapperKey.MappingData.MappingContext.PlanSettings.LazyLoadRepeatMappingFuncs); _repeatedMappingFuncsByKey.GetOrAdd(mapperKey, _ => mapperFunc); } diff --git a/AgileMapper/ObjectPopulation/ObjectMapperData.cs b/AgileMapper/ObjectPopulation/ObjectMapperData.cs index 094d7464d..ceff43f05 100644 --- a/AgileMapper/ObjectPopulation/ObjectMapperData.cs +++ b/AgileMapper/ObjectPopulation/ObjectMapperData.cs @@ -15,6 +15,7 @@ namespace AgileObjects.AgileMapper.ObjectPopulation using Extensions.Internal; using MapperKeys; using Members; + using Members.Extensions; using Members.Sources; using NetStandardPolyfills; using ReadableExpressions.Extensions; @@ -27,7 +28,7 @@ internal class ObjectMapperData : MemberMapperDataBase, IMemberMapperData private static readonly MethodInfo _mapRepeatedElementMethod = typeof(IObjectMappingDataUntyped).GetPublicInstanceMethod("MapRepeated", parameterCount: 4); - private readonly LabelTarget _returnLabelTarget; + private LabelTarget _returnLabelTarget; private Expression _rootMappingDataObject; private ObjectMapperData _entryPointMapperData; private Expression _targetInstance; @@ -74,8 +75,7 @@ private ObjectMapperData( ElementKey = GetElementKeyAccess(); ParentObject = GetParentObjectAccess(); } - - _returnLabelTarget = Expression.Label(TargetType, "Return"); + _mappedObjectCachingMode = MapperContext.UserConfigurations.CacheMappedObjects(this); if (targetMember.IsEnumerable) @@ -667,7 +667,7 @@ public MethodCallExpression GetMapRepeatedCall( /// 's LabelTarget. /// public Expression GetReturnExpression(Expression value) - => Expression.Return(_returnLabelTarget, value, TargetType); + => Expression.Return(ReturnLabelTarget, value, TargetType); /// /// Creates a LabelExpression for this 's LabelTarget, with @@ -681,7 +681,12 @@ public Expression GetReturnExpression(Expression value) /// . /// public Expression GetReturnLabel(Expression defaultValue) - => Expression.Label(_returnLabelTarget, defaultValue); + => Expression.Label(ReturnLabelTarget, defaultValue); + + private LabelTarget ReturnLabelTarget + => _returnLabelTarget ??= Expression.Label(TargetType, "Return"); + + public bool ReturnLabelUsed => _returnLabelTarget != null; public IQualifiedMemberContext WithNoTargetMember() { diff --git a/AgileMapper/ObjectPopulation/ObjectMappingData.cs b/AgileMapper/ObjectPopulation/ObjectMappingData.cs index 817928197..74a76245a 100644 --- a/AgileMapper/ObjectPopulation/ObjectMappingData.cs +++ b/AgileMapper/ObjectPopulation/ObjectMappingData.cs @@ -12,6 +12,7 @@ namespace AgileObjects.AgileMapper.ObjectPopulation using Extensions.Internal; using MapperKeys; using Members; + using Members.Extensions; using NetStandardPolyfills; using Validation; #if NET35 diff --git a/AgileMapper/ObjectPopulation/ObjectMappingDataFactory.cs b/AgileMapper/ObjectPopulation/ObjectMappingDataFactory.cs index f2395bafb..dccf05d01 100644 --- a/AgileMapper/ObjectPopulation/ObjectMappingDataFactory.cs +++ b/AgileMapper/ObjectPopulation/ObjectMappingDataFactory.cs @@ -13,12 +13,13 @@ namespace AgileObjects.AgileMapper.ObjectPopulation using Extensions.Internal; using MapperKeys; using Members; + using Members.Extensions; using Members.Sources; using NetStandardPolyfills; - internal class ObjectMappingDataFactory : IObjectMappingDataFactoryBridge + internal class ObjectMappingDataFactory : IUntypedObjectMappingDataFactory { - private static readonly IObjectMappingDataFactoryBridge _bridge = new ObjectMappingDataFactory(); + private static readonly IUntypedObjectMappingDataFactory _bridge = new ObjectMappingDataFactory(); public static ObjectMappingData ForRootFixedTypes( IMappingContext mappingContext) @@ -48,7 +49,7 @@ public static ObjectMappingData ForRootFixedTypes { - var bridgeParameter = Expression.Parameter(typeof(IObjectMappingDataFactoryBridge), "bridge"); + var bridgeParameter = Expression.Parameter(typeof(IUntypedObjectMappingDataFactory), "bridge"); var childMembersSourceParameter = Expression.Parameter(typeof(object), "childMembersSource"); var parentParameter = Expression.Parameter(typeof(object), nameof(parent)); @@ -137,7 +138,7 @@ public static IObjectMappingData ForChild( childMembersSourceParameter, parentParameter); - var typedForChildLambda = Expression.Lambda>( + var typedForChildLambda = Expression.Lambda>( typedForChildCall, bridgeParameter, childMembersSourceParameter, @@ -151,7 +152,7 @@ public static IObjectMappingData ForChild( return (IObjectMappingData)typedForChildCaller.Invoke(_bridge, membersSource, parent); } - object IObjectMappingDataFactoryBridge.ForChild(object childMembersSource, object parent) + object IUntypedObjectMappingDataFactory.ForChild(object childMembersSource, object parent) { var mapperKey = new ChildObjectMapperKey( MappingTypes.For(default(TSource), default(TTarget)), @@ -208,7 +209,7 @@ public static IObjectMappingData ForElement( var typedForElementCaller = GlobalContext.Instance.Cache.GetOrAdd(key, k => { - var bridgeParameter = Expression.Parameter(typeof(IObjectMappingDataFactoryBridge), "bridge"); + var bridgeParameter = Expression.Parameter(typeof(IUntypedObjectMappingDataFactory), "bridge"); var parentParameter = Expression.Parameter(typeof(object), "parent"); var typedForElementMethod = bridgeParameter.Type @@ -220,7 +221,7 @@ public static IObjectMappingData ForElement( typedForElementMethod, parentParameter); - var typedForElementLambda = Expression.Lambda>( + var typedForElementLambda = Expression.Lambda>( typedForElementCall, bridgeParameter, parentParameter); @@ -231,7 +232,7 @@ public static IObjectMappingData ForElement( return (IObjectMappingData)typedForElementCaller.Invoke(_bridge, parent); } - object IObjectMappingDataFactoryBridge.ForElement(object parent) + object IUntypedObjectMappingDataFactory.ForElement(object parent) { var mappingData = (IObjectMappingData)parent; var source = mappingData.GetSource(); @@ -330,14 +331,14 @@ private static IObjectMappingData Create( parent); } - private static Func GetPartialTrustMappingDataCreator( + private static Func GetPartialTrustMappingDataCreator( MappingTypes mappingTypes) { var createCallerKey = DeclaredAndRuntimeTypesKey.For(mappingTypes); var createCallerFunc = GlobalContext.Instance.Cache.GetOrAdd(createCallerKey, k => { - var bridgeParameter = Expression.Parameter(typeof(IObjectMappingDataFactoryBridge), "bridge"); + var bridgeParameter = Expression.Parameter(typeof(IUntypedObjectMappingDataFactory), "bridge"); var sourceParameter = Parameters.Create(k.DeclaredSourceType, "source"); var targetParameter = Parameters.Create(k.DeclaredTargetType, "target"); var elementIndexParameter = Expression.Parameter(typeof(int?), "i"); @@ -366,7 +367,7 @@ private static IObjectMappingData Create( parentParameter); var createLambda = Expression - .Lambda>( + .Lambda>( createCall, bridgeParameter, sourceParameter, @@ -383,7 +384,7 @@ private static IObjectMappingData Create( return createCallerFunc; } - object IObjectMappingDataFactoryBridge.CreateMappingData( + object IUntypedObjectMappingDataFactory.CreateMappingData( TDeclaredSource source, TDeclaredTarget target, int? elementIndex, diff --git a/AgileMapper/ObjectPopulation/ObjectMappingExceptionData.cs b/AgileMapper/ObjectPopulation/ObjectMappingExceptionData.cs index d3ca54174..b95962262 100644 --- a/AgileMapper/ObjectPopulation/ObjectMappingExceptionData.cs +++ b/AgileMapper/ObjectPopulation/ObjectMappingExceptionData.cs @@ -32,7 +32,5 @@ public ObjectMappingExceptionData(IMappingData mappingData, Ex object IMappingExceptionData.Target => Target; public Exception Exception { get; } - - int? IMappingExceptionData.EnumerableIndex => ElementIndex; } } \ No newline at end of file diff --git a/AgileMapper/ObjectPopulation/RepeatedMappings/IRepeatedMapperFunc.cs b/AgileMapper/ObjectPopulation/RepeatedMappings/IRepeatedMapperFunc.cs index bacd814f4..7739afd8c 100644 --- a/AgileMapper/ObjectPopulation/RepeatedMappings/IRepeatedMapperFunc.cs +++ b/AgileMapper/ObjectPopulation/RepeatedMappings/IRepeatedMapperFunc.cs @@ -1,12 +1,20 @@ namespace AgileObjects.AgileMapper.ObjectPopulation.RepeatedMappings { using System; +#if NET35 + using Microsoft.Scripting.Ast; +#else + using System.Linq.Expressions; +#endif - internal interface IRepeatedMapperFunc : IObjectMapperFunc + internal interface IRepeatedMapperFunc : IObjectMapperFuncBase { Type SourceType { get; } Type TargetType { get; } + bool HasDerivedTypes { get; } + + LambdaExpression Mapping { get; } } } \ No newline at end of file diff --git a/AgileMapper/ObjectPopulation/RepeatedMappings/RepeatedMapperFunc.cs b/AgileMapper/ObjectPopulation/RepeatedMappings/RepeatedMapperFunc.cs index 939133cf4..a1b42dedd 100644 --- a/AgileMapper/ObjectPopulation/RepeatedMappings/RepeatedMapperFunc.cs +++ b/AgileMapper/ObjectPopulation/RepeatedMappings/RepeatedMapperFunc.cs @@ -6,6 +6,7 @@ namespace AgileObjects.AgileMapper.ObjectPopulation.RepeatedMappings #else using System.Linq.Expressions; #endif + using Extensions.Internal; using Members; internal class RepeatedMapperFunc : IRepeatedMapperFunc @@ -16,10 +17,11 @@ internal class RepeatedMapperFunc : IRepeatedMapperF public RepeatedMapperFunc(IObjectMappingData mappingData, bool lazyLoadFuncs) { + _mapperData = mappingData.MapperData; + if (lazyLoadFuncs) { _mappingFuncLock = new object(); - _mapperData = mappingData.MapperData; _mapperData.SetEntryPoint(); return; } @@ -27,12 +29,14 @@ public RepeatedMapperFunc(IObjectMappingData mappingData, bool lazyLoadFuncs) CreateMapperFunc(mappingData); } - public Expression Mapping { get; private set; } + public LambdaExpression Mapping { get; private set; } public Type SourceType => typeof(TChildSource); public Type TargetType => typeof(TChildTarget); + public bool HasDerivedTypes => _mapperData.DerivedMapperDatas.Any(); + public object Map(IObjectMappingData mappingData) { var typedData = (ObjectMappingData)mappingData; diff --git a/AgileMapper/ObjectPopulation/SimpleMemberMapperData.cs b/AgileMapper/ObjectPopulation/SimpleMemberMapperData.cs index 36e98b2c7..3ae10eabc 100644 --- a/AgileMapper/ObjectPopulation/SimpleMemberMapperData.cs +++ b/AgileMapper/ObjectPopulation/SimpleMemberMapperData.cs @@ -7,6 +7,7 @@ namespace AgileObjects.AgileMapper.ObjectPopulation #endif using Extensions.Internal; using Members; + using Members.Extensions; using Members.Sources; internal class SimpleMemberMapperData : MemberMapperDataBase, IMemberMapperData diff --git a/AgileMapper/Plans/IMappingPlan.cs b/AgileMapper/Plans/IMappingPlan.cs index 7e15ca6e6..d493ac9a5 100644 --- a/AgileMapper/Plans/IMappingPlan.cs +++ b/AgileMapper/Plans/IMappingPlan.cs @@ -1,15 +1,29 @@ namespace AgileObjects.AgileMapper.Plans { -#if NET35 - using Microsoft.Scripting.Ast; -#else - using System.Linq.Expressions; -#endif + using System.Collections.Generic; - internal interface IMappingPlan + /// + /// Implementing classes will describe a plan for mapping from one type to another with a + /// particular rule set. + /// + public interface IMappingPlan : IEnumerable { - string GetDescription(); - - Expression GetExpression(); + /// + /// Gets the name of the rule set (CreateNew, Overwrite, etc) used to create the mapping + /// described by this . + /// + string RuleSetName { get; } + + /// + /// Gets the root describing the plan to map the root source + /// and target objects. + /// + IMappingPlanFunction Root { get; } + + /// + /// Gets a source-code string translation of this . + /// + /// A source-code string translation of this . + string ToSourceCode(); } } \ No newline at end of file diff --git a/AgileMapper/Plans/IMappingPlanFunction.cs b/AgileMapper/Plans/IMappingPlanFunction.cs index 00d5d7976..7b9f36629 100644 --- a/AgileMapper/Plans/IMappingPlanFunction.cs +++ b/AgileMapper/Plans/IMappingPlanFunction.cs @@ -1,15 +1,57 @@ namespace AgileObjects.AgileMapper.Plans { + using System; #if NET35 using Microsoft.Scripting.Ast; #else using System.Linq.Expressions; #endif + using ReadableExpressions; - internal interface IMappingPlanFunction + /// + /// Implementing classes will describe a mapping function used to map from one type to another + /// with a particular rule set. + /// + public interface IMappingPlanFunction { - Expression GetExpression(); + /// + /// Gets a value indicating whether this describes the + /// root mapping of its . + /// + bool IsRoot { get; } - string GetDescription(); + /// + /// Gets the source type from which this will perform a + /// mapping. + /// + Type SourceType { get; } + + /// + /// Gets the target type to which this will perform a + /// mapping. + /// + Type TargetType { get; } + + /// + /// Gets a value indicating whether this includes mapping + /// of the and . + /// + bool HasDerivedTypes { get; } + + /// + /// Gets an Expression summarising the . + /// + CommentExpression Summary { get; } + + /// + /// Gets an Expression describing the 's mapping. + /// + LambdaExpression Mapping { get; } + + /// + /// Gets a source-code string translation of this . + /// + /// A source-code string translation of this . + string ToSourceCode(); } } \ No newline at end of file diff --git a/AgileMapper/Plans/MappingPlan.cs b/AgileMapper/Plans/MappingPlan.cs index 76d412418..c964dc3ce 100644 --- a/AgileMapper/Plans/MappingPlan.cs +++ b/AgileMapper/Plans/MappingPlan.cs @@ -1,7 +1,9 @@ namespace AgileObjects.AgileMapper.Plans { using System; + using System.Collections; using System.Collections.Generic; + using System.Linq; #if NET35 using Microsoft.Scripting.Ast; #else @@ -21,10 +23,10 @@ public class MappingPlan : IMappingPlan internal MappingPlan(IObjectMapper cachedMapper) { - _mappingPlanFunctions = new List - { - new RootMapperMappingPlanFunction(cachedMapper) - }; + RuleSetName = cachedMapper.MapperData.RuleSet.Name; + Root = new RootMapperMappingPlanFunction(cachedMapper); + + _mappingPlanFunctions = new List { Root }; if (cachedMapper.MapperData.HasRepeatedMapperFuncs) { @@ -46,7 +48,7 @@ public static implicit operator string(MappingPlan mappingPlan) { return mappingPlan ._mappingPlanFunctions - .ProjectToArray(pd => pd.GetDescription()) + .ProjectToArray(pf => pf.ToSourceCode()) .Join(Environment.NewLine + Environment.NewLine); } @@ -59,16 +61,21 @@ public static implicit operator Expression(MappingPlan mappingPlan) { return Expression.Block(mappingPlan ._mappingPlanFunctions - .ProjectToArray(pd => pd.GetExpression())); + .SelectMany(mpf => new Expression[] { mpf.Summary, mpf.Mapping })); } - #region IMappingPlan Members + /// + public string RuleSetName { get; } + + /// + public IMappingPlanFunction Root { get; } + + string IMappingPlan.ToSourceCode() => this; - string IMappingPlan.GetDescription() => this; - - Expression IMappingPlan.GetExpression() => this; + IEnumerator IEnumerable.GetEnumerator() => _mappingPlanFunctions.GetEnumerator(); - #endregion + IEnumerator IEnumerable.GetEnumerator() + => _mappingPlanFunctions.GetEnumerator(); /// /// Returns the string representation of the . diff --git a/AgileMapper/Plans/MappingPlanSet.cs b/AgileMapper/Plans/MappingPlanSet.cs index be244998e..59507a638 100644 --- a/AgileMapper/Plans/MappingPlanSet.cs +++ b/AgileMapper/Plans/MappingPlanSet.cs @@ -1,6 +1,8 @@ namespace AgileObjects.AgileMapper.Plans { + using System.Collections; using System.Collections.Generic; + using System.Collections.ObjectModel; using System.Linq; using Extensions; using Extensions.Internal; @@ -15,7 +17,7 @@ /// Contains sets of details of mapping plans for mappings between a particular source and target types, /// for particular mapping types (create new, merge, overwrite). /// - public class MappingPlanSet + public class MappingPlanSet : IEnumerable { private readonly IEnumerable _mappingPlans; @@ -45,26 +47,39 @@ internal static MappingPlanSet For(MapperContext mapperContext) public static implicit operator string(MappingPlanSet mappingPlans) { return mappingPlans - ._mappingPlans - .Project(plan => plan.GetDescription()) + .Project(plan => plan.ToSourceCode()) .Join(NewLine + NewLine); } /// - /// Converts the given MappingPlanSet to its Expression - /// representation. + /// Converts the given MappingPlanSet to a collection + /// of Expressions. /// /// The to convert. /// - /// The Expression representation of the MappingPlanSet. + /// A collection of Expressions representing this MappingPlanSet. /// - public static implicit operator Expr(MappingPlanSet mappingPlans) + public static implicit operator ReadOnlyCollection(MappingPlanSet mappingPlans) { - return Expr.Block(mappingPlans - ._mappingPlans - .Project(plan => plan.GetExpression())); + return new ReadOnlyCollection(mappingPlans + .Select(mp => + { + var functionBlocks = mp + .Select(mpf => (Expr)Expr.Block(mpf.Summary, mpf.Mapping)) + .ToList(); + + return functionBlocks.HasOne() + ? functionBlocks.First() + : Expr.Block(functionBlocks); + }) + .ToList()); } + IEnumerator IEnumerable.GetEnumerator() => _mappingPlans.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + => _mappingPlans.GetEnumerator(); + /// /// Returns the string representation of the . /// diff --git a/AgileMapper/Plans/MappingPlanSettings.cs b/AgileMapper/Plans/MappingPlanSettings.cs new file mode 100644 index 000000000..e59cebd6a --- /dev/null +++ b/AgileMapper/Plans/MappingPlanSettings.cs @@ -0,0 +1,60 @@ +namespace AgileObjects.AgileMapper.Plans +{ + /// + /// Provides options to control how a mapping plan should be created. + /// + public class MappingPlanSettings + { + /// + /// Wrapper class for the default instances used when + /// creating mapping plans. + /// + public static class Default + { + /// + /// Gets or sets the default to use when creating a + /// mapping plan upfront with Mapper.GetPlanFor<TSource>().To<TTarget>(). + /// + public static readonly MappingPlanSettings EagerPlanned = new() + { + LazyCompile = false, + CommentUnmappableMembers = true, + CommentUnmappedMembers = true, + LazyLoadRepeatMappingFuncs = false + }; + + internal static readonly MappingPlanSettings LazyPlanned = new() + { + LazyCompile = false, + CommentUnmappableMembers = false, + CommentUnmappedMembers = false, + LazyLoadRepeatMappingFuncs = true + }; + } + + /// + /// Gets or sets a value indicating whether the mapping plan should lazy-compile its + /// generated Expression tree into the Func with which mapping is performed. If true, the + /// mapping Func will be compiled from the mapping Expression tree when it is first needed, + /// instead of when the plan is created. Defaults to false for an upfront-cached mapping + /// plan. + /// + public bool LazyCompile { get; set; } + + /// + /// Gets or sets a value indicating whether to include code comments explaining why any + /// unmappable members cannot be mapped, e.g if a complex type member has no usable + /// constructor. Defaults to true for an upfront-cached mapping plan. + /// + public bool CommentUnmappableMembers { get; set; } + + /// + /// Gets or sets a value indicating whether to include code comments noting why any unmapped + /// members are not mapped, e.g if they've been explicitly ignored, or have no matching + /// source values. Defaults to true for an upfront-cached mapping plan. + /// + public bool CommentUnmappedMembers { get; set; } + + internal bool LazyLoadRepeatMappingFuncs { get; set; } + } +} diff --git a/AgileMapper/Plans/RepeatedMappingMappingPlanFunction.cs b/AgileMapper/Plans/RepeatedMappingMappingPlanFunction.cs index a8237825d..697518030 100644 --- a/AgileMapper/Plans/RepeatedMappingMappingPlanFunction.cs +++ b/AgileMapper/Plans/RepeatedMappingMappingPlanFunction.cs @@ -12,44 +12,41 @@ internal class RepeatedMappingMappingPlanFunction : IMappingPlanFunction { - private readonly Type _sourceType; - private readonly Type _targetType; - private readonly Expression _mapping; + private readonly IRepeatedMapperFunc _mapperFunc; + private CommentExpression _summary; public RepeatedMappingMappingPlanFunction(IRepeatedMapperFunc mapperFunc) { - _sourceType = mapperFunc.SourceType; - _targetType = mapperFunc.TargetType; - _mapping = mapperFunc.Mapping; + _mapperFunc = mapperFunc; } - public Expression GetExpression() - { - var description = GetMappingDescription(); + public bool IsRoot => false; - return Expression.Block( - ReadableExpression.Comment(description), - _mapping); - } + public Type SourceType => _mapperFunc.SourceType; - public string GetDescription() - { - var description = GetMappingDescription(linePrefix: "// "); + public Type TargetType => _mapperFunc.TargetType; - return description + _mapping.ToReadableString(); - } + public bool HasDerivedTypes => _mapperFunc.HasDerivedTypes; + + public CommentExpression Summary + => _summary ??= ReadableExpression.Comment(GetMappingDescription()); private string GetMappingDescription(string linePrefix = null) { return $@" -{linePrefix}- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{linePrefix}- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{linePrefix}Map {_sourceType.GetFriendlyName()} -> {_targetType.GetFriendlyName()} +{linePrefix}Map {SourceType.GetFriendlyName()} -> {TargetType.GetFriendlyName()} {linePrefix}Repeated Mapping Mapper -{linePrefix}- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{linePrefix}- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "; } + + public LambdaExpression Mapping => _mapperFunc.Mapping; + + public string ToSourceCode() + { + var description = GetMappingDescription(linePrefix: "// "); + + return description + Mapping.ToReadableString(); + } } } \ No newline at end of file diff --git a/AgileMapper/Plans/RootMapperMappingPlanFunction.cs b/AgileMapper/Plans/RootMapperMappingPlanFunction.cs index 6159b6dfd..65431f707 100644 --- a/AgileMapper/Plans/RootMapperMappingPlanFunction.cs +++ b/AgileMapper/Plans/RootMapperMappingPlanFunction.cs @@ -1,5 +1,7 @@ namespace AgileObjects.AgileMapper.Plans { + using System; + using Extensions.Internal; #if NET35 using Microsoft.Scripting.Ast; #else @@ -13,7 +15,9 @@ internal class RootMapperMappingPlanFunction : IMappingPlanFunction { private readonly ObjectMapperData _mapperData; - private readonly Expression _mapping; + private readonly LambdaExpression _mapping; + private CommentExpression _summary; + private LambdaExpression _finalMapping; public RootMapperMappingPlanFunction(IObjectMapper mapper) { @@ -21,41 +25,40 @@ public RootMapperMappingPlanFunction(IObjectMapper mapper) _mapping = mapper.GetMappingLambda(); } - public Expression GetExpression() - { - var description = GetMappingDescription(); - var mapping = GetFinalMappingExpression(); + public bool IsRoot => true; - return Expression.Block( - ReadableExpression.Comment(description), - mapping); - } + public Type SourceType => _mapperData.SourceType; - public string GetDescription() - { - var description = GetMappingDescription(linePrefix: "// "); - var mapping = GetFinalMappingExpression(); + public Type TargetType => _mapperData.TargetType; - return description + mapping.ToReadableString(); - } + public bool HasDerivedTypes => _mapperData.DerivedMapperDatas.Any(); + + public CommentExpression Summary + => _summary ??= ReadableExpression.Comment(GetMappingDescription()); private string GetMappingDescription(string linePrefix = null) { - var sourceType = _mapperData.SourceType.GetFriendlyName(); - var targetType = _mapperData.TargetType.GetFriendlyName(); + var sourceTypeName = SourceType.GetFriendlyName(); + var targetTypeName = TargetType.GetFriendlyName(); return $@" -{linePrefix}- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{linePrefix}- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{linePrefix}Map {sourceType} -> {targetType} +{linePrefix}Map {sourceTypeName} -> {targetTypeName} {linePrefix}Rule Set: {_mapperData.RuleSet.Name} -{linePrefix}- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{linePrefix}- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "; } - private Expression GetFinalMappingExpression() + public LambdaExpression Mapping + => _finalMapping ??= GetFinalMappingExpression(); + + public string ToSourceCode() + { + var description = GetMappingDescription(linePrefix: "// "); + + return description + Mapping.ToReadableString(); + } + + private LambdaExpression GetFinalMappingExpression() { var mappingWithEnumMismatches = EnumMappingMismatchFinder.Process(_mapping, _mapperData); diff --git a/AgileMapper/Properties/AssemblyInfo.cs b/AgileMapper/Properties/AssemblyInfo.cs index ef2e6891b..821441a79 100644 --- a/AgileMapper/Properties/AssemblyInfo.cs +++ b/AgileMapper/Properties/AssemblyInfo.cs @@ -4,7 +4,7 @@ using System.Security; [assembly: AssemblyTitle("AgileObjects.AgileMapper")] -[assembly: AssemblyDescription("A zero-configuration, highly-configurable object-object mapper with viewable execution plans. Performs deep clones, updates and merges via extension methods, or a static or instance API. Targets .NET Standard 1.0+ and .NET 3.5+")] +[assembly: AssemblyDescription("A zero-configuration, highly-configurable, unopinionated object mapper with viewable execution plans. Flattens, unflattens, deep clones, merges, updates and projects queries. Targets .NET 3.5+ and .NET Standard 1.0+")] [assembly: AllowPartiallyTrustedCallers] [assembly: CLSCompliant(true)] diff --git a/AgileMapper/Queryables/Converters/ComplexTypeToNullComparisonConverter.cs b/AgileMapper/Queryables/Converters/ComplexTypeToNullComparisonConverter.cs index c59ff778f..a18b7ccc3 100644 --- a/AgileMapper/Queryables/Converters/ComplexTypeToNullComparisonConverter.cs +++ b/AgileMapper/Queryables/Converters/ComplexTypeToNullComparisonConverter.cs @@ -8,6 +8,7 @@ #endif using Extensions.Internal; using Members; + using Members.Extensions; using ReadableExpressions.Extensions; internal static class ComplexTypeToNullComparisonConverter diff --git a/AgileMapper/Queryables/Converters/ToStringConverter.cs b/AgileMapper/Queryables/Converters/ToStringConverter.cs index b3d50f34e..e71eb345f 100644 --- a/AgileMapper/Queryables/Converters/ToStringConverter.cs +++ b/AgileMapper/Queryables/Converters/ToStringConverter.cs @@ -1,14 +1,13 @@ namespace AgileObjects.AgileMapper.Queryables.Converters { using System; - using Extensions.Internal; - using NetStandardPolyfills; - using ReadableExpressions.Extensions; #if NET35 using Microsoft.Scripting.Ast; #else using System.Linq.Expressions; #endif + using Extensions.Internal; + using NetStandardPolyfills; internal static class ToStringConverter { diff --git a/AgileMapper/Queryables/Settings/EntityFramework/Ef5QueryProviderSettings.cs b/AgileMapper/Queryables/Settings/EntityFramework/Ef5QueryProviderSettings.cs index de51dd668..8725a2b48 100644 --- a/AgileMapper/Queryables/Settings/EntityFramework/Ef5QueryProviderSettings.cs +++ b/AgileMapper/Queryables/Settings/EntityFramework/Ef5QueryProviderSettings.cs @@ -10,7 +10,6 @@ using System.Reflection; using Extensions.Internal; using NetStandardPolyfills; - using ReadableExpressions.Extensions; internal class Ef5QueryProviderSettings : LegacyEfQueryProviderSettings { diff --git a/AgileMapper/SimpleMappingContext.cs b/AgileMapper/SimpleMappingContext.cs index fc045a455..f7937750c 100644 --- a/AgileMapper/SimpleMappingContext.cs +++ b/AgileMapper/SimpleMappingContext.cs @@ -1,20 +1,28 @@ namespace AgileObjects.AgileMapper { + using Plans; + internal class SimpleMappingContext : IMappingContext { public SimpleMappingContext(MappingRuleSet ruleSet, MapperContext mapperContext) + : this(ruleSet, MappingPlanSettings.Default.LazyPlanned, mapperContext) + { + } + + public SimpleMappingContext( + MappingRuleSet ruleSet, + MappingPlanSettings planSettings, + MapperContext mapperContext) { MapperContext = mapperContext; RuleSet = ruleSet; - IgnoreUnsuccessfulMemberPopulations = true; + PlanSettings = planSettings; } public MapperContext MapperContext { get; } public MappingRuleSet RuleSet { get; } - public bool IgnoreUnsuccessfulMemberPopulations { get; set; } - - public bool LazyLoadRepeatMappingFuncs => false; + public MappingPlanSettings PlanSettings { get; } } } \ No newline at end of file diff --git a/AgileMapper/TypeConversion/ConverterSet.cs b/AgileMapper/TypeConversion/ConverterSet.cs index 6cc45f31b..6762e0ba6 100644 --- a/AgileMapper/TypeConversion/ConverterSet.cs +++ b/AgileMapper/TypeConversion/ConverterSet.cs @@ -79,7 +79,10 @@ private IValueConverter GetConverterOrNull(Type sourceType, Type targetType) return _converters.FirstOrDefault(c => c.CanConvert(sourceType, targetType)); } - public Expression GetConversion(Expression sourceValue, Type targetType) + public Expression GetConversion( + Expression sourceValue, + Type targetType, + MappingRuleSet ruleSet) { if (sourceValue.Type == targetType) { @@ -94,7 +97,20 @@ public Expression GetConversion(Expression sourceValue, Type targetType) } var converter = GetConverterOrNull(sourceValue.Type, targetType); - var conversion = converter?.GetConversion(sourceValue, targetType); + + if (converter == null) + { + return null; + } + + var useSingleStatement = + ruleSet == MappingRuleSet.All || + ruleSet.Settings.UseSingleRootMappingExpression; + + var conversion = converter.GetConversion( + sourceValue, + targetType, + useSingleStatement); return conversion; } diff --git a/AgileMapper/TypeConversion/FallbackNonSimpleTypeValueConverter.cs b/AgileMapper/TypeConversion/FallbackNonSimpleTypeValueConverter.cs index b6b0a74f6..d1aa74783 100644 --- a/AgileMapper/TypeConversion/FallbackNonSimpleTypeValueConverter.cs +++ b/AgileMapper/TypeConversion/FallbackNonSimpleTypeValueConverter.cs @@ -32,6 +32,12 @@ public bool CanConvert(Type nonNullableSourceType, Type nonNullableTargetType) return true; } - public Expression GetConversion(Expression sourceValue, Type targetType) => sourceValue; + public Expression GetConversion( + Expression sourceValue, + Type targetType, + bool useSingleStatement) + { + return sourceValue; + } } } \ No newline at end of file diff --git a/AgileMapper/TypeConversion/IValueConverter.cs b/AgileMapper/TypeConversion/IValueConverter.cs index c8d79d45a..fa2090acd 100644 --- a/AgileMapper/TypeConversion/IValueConverter.cs +++ b/AgileMapper/TypeConversion/IValueConverter.cs @@ -30,10 +30,15 @@ public interface IValueConverter /// /// The source value to convert. /// The target type to which to convert to . + /// + /// Whether the conversion Expression to create should convert the values using a single + /// statement, or if the context supports multiple statements, e.g. query projection + /// vs in-memory mapping. + /// /// /// An Expression converting the given to the given /// . /// - Expression GetConversion(Expression sourceValue, Type targetType); + Expression GetConversion(Expression sourceValue, Type targetType, bool useSingleStatement); } } \ No newline at end of file diff --git a/AgileMapper/TypeConversion/NumericValueIsInRangeComparison.cs b/AgileMapper/TypeConversion/NumericValueIsInRangeComparison.cs index 6b854a565..3b6816c48 100644 --- a/AgileMapper/TypeConversion/NumericValueIsInRangeComparison.cs +++ b/AgileMapper/TypeConversion/NumericValueIsInRangeComparison.cs @@ -1,14 +1,13 @@ namespace AgileObjects.AgileMapper.TypeConversion { using System; - using Extensions.Internal; - using NetStandardPolyfills; - using ReadableExpressions.Extensions; #if NET35 using Microsoft.Scripting.Ast; #else using System.Linq.Expressions; #endif + using Extensions.Internal; + using NetStandardPolyfills; internal static class NumericValueIsInRangeComparison { diff --git a/AgileMapper/TypeConversion/OperatorConverter.cs b/AgileMapper/TypeConversion/OperatorConverter.cs index c73efdf06..0f838444d 100644 --- a/AgileMapper/TypeConversion/OperatorConverter.cs +++ b/AgileMapper/TypeConversion/OperatorConverter.cs @@ -9,7 +9,6 @@ namespace AgileObjects.AgileMapper.TypeConversion #endif using System.Reflection; using NetStandardPolyfills; - using ReadableExpressions.Extensions; internal struct OperatorConverter : IValueConverter { @@ -45,7 +44,7 @@ public static MethodInfo GetOperatorOrNull( private static MethodInfo GetOperatorOrNull(Type subjectType, Func matcher) => subjectType.GetOperators().FirstOrDefault(matcher.Invoke); - public Expression GetConversion(Expression sourceValue, Type targetType) + public Expression GetConversion(Expression sourceValue, Type targetType, bool useSingleStatement) { var nonNullableSourceType = sourceValue.Type.GetNonNullableType(); var nonNullableTargetType = targetType.GetNonNullableType(); diff --git a/AgileMapper/TypeConversion/ToBoolConverter.cs b/AgileMapper/TypeConversion/ToBoolConverter.cs index 61a66f2cf..4a002a7b8 100644 --- a/AgileMapper/TypeConversion/ToBoolConverter.cs +++ b/AgileMapper/TypeConversion/ToBoolConverter.cs @@ -22,7 +22,10 @@ public bool CanConvert(Type nonNullableSourceType, Type nonNullableTargetType) ToStringConverter.HasNativeStringRepresentation(nonNullableSourceType)); } - public Expression GetConversion(Expression sourceValue, Type targetType) + public Expression GetConversion( + Expression sourceValue, + Type targetType, + bool useSingleStatement) { if (sourceValue.Type == typeof(bool?)) { diff --git a/AgileMapper/TypeConversion/ToCharacterConverter.cs b/AgileMapper/TypeConversion/ToCharacterConverter.cs index 4affd8823..2b8b563b4 100644 --- a/AgileMapper/TypeConversion/ToCharacterConverter.cs +++ b/AgileMapper/TypeConversion/ToCharacterConverter.cs @@ -21,7 +21,10 @@ public bool CanConvert(Type nonNullableSourceType, Type nonNullableTargetType) (Array.IndexOf(Constants.NumericTypes, nonNullableSourceType) != -1)); } - public Expression GetConversion(Expression sourceValue, Type targetType) + public Expression GetConversion( + Expression sourceValue, + Type targetType, + bool useSingleStatement) { if (sourceValue.Type == typeof(char?)) { diff --git a/AgileMapper/TypeConversion/ToEnumConverter.cs b/AgileMapper/TypeConversion/ToEnumConverter.cs index 556d0b117..1fe6b1e36 100644 --- a/AgileMapper/TypeConversion/ToEnumConverter.cs +++ b/AgileMapper/TypeConversion/ToEnumConverter.cs @@ -14,6 +14,12 @@ using Extensions.Internal; using NetStandardPolyfills; using ReadableExpressions.Extensions; + using static System.Convert; +#if NET35 + using static Microsoft.Scripting.Ast.Expression; +#else + using static System.Linq.Expressions.Expression; +#endif internal class ToEnumConverter : IValueConverter { @@ -35,7 +41,10 @@ public bool CanConvert(Type nonNullableSourceType, Type nonNullableTargetType) ToStringConverter.HasNativeStringRepresentation(nonNullableSourceType); } - public Expression GetConversion(Expression sourceValue, Type targetEnumType) + public Expression GetConversion( + Expression sourceValue, + Type targetEnumType, + bool useSingleStatement) { var fallbackValue = targetEnumType.ToDefaultExpression(); var nonNullableSourceType = sourceValue.Type.GetNonNullableType(); @@ -65,13 +74,15 @@ public Expression GetConversion(Expression sourceValue, Type targetEnumType) sourceValue, fallbackValue, nonNullableSourceType, - nonNullableTargetEnumType); + nonNullableTargetEnumType, + useSingleStatement); } return GetStringValueConversion( sourceValue, fallbackValue, - nonNullableTargetEnumType); + nonNullableTargetEnumType, + useSingleStatement); } private static Expression GetFlagsEnumConversion( @@ -83,7 +94,7 @@ private static Expression GetFlagsEnumConversion( var enumTypeName = GetVariableNameFor(nonNullableTargetEnumType); var underlyingEnumType = Enum.GetUnderlyingType(nonNullableTargetEnumType); - var enumValueVariable = Expression.Variable(underlyingEnumType, enumTypeName + "Value"); + var enumValueVariable = Variable(underlyingEnumType, enumTypeName + "Value"); var underlyingTypeDefault = underlyingEnumType.ToDefaultExpression(); var assignEnumValue = enumValueVariable.AssignTo(underlyingTypeDefault); @@ -105,25 +116,25 @@ private static Expression GetFlagsEnumConversion( var sourceValuesVariable = GetEnumValuesVariable(enumTypeName, typeof(string)); - var splitSourceValueCall = Expression.Call( + var splitSourceValueCall = Call( sourceValue, typeof(string).GetPublicInstanceMethod("Split", typeof(char[])), - Expression.NewArrayInit(typeof(char), ','.ToConstantExpression())); + NewArrayInit(typeof(char), ','.ToConstantExpression())); var assignSourceValues = GetValuesEnumeratorAssignment(sourceValuesVariable, splitSourceValueCall); var ifNotMoveNextBreak = GetLoopExitCheck(sourceValuesVariable, out var loopBreakTarget); - var localSourceValueVariable = Expression.Variable(typeof(string), enumTypeName); - var enumeratorCurrent = Expression.Property(sourceValuesVariable, "Current"); + var localSourceValueVariable = Variable(typeof(string), enumTypeName); + var enumeratorCurrent = Property(sourceValuesVariable, "Current"); var stringTrimMethod = typeof(string).GetPublicInstanceMethod("Trim", parameterCount: 0); - var currentTrimmed = Expression.Call(enumeratorCurrent, stringTrimMethod); + var currentTrimmed = Call(enumeratorCurrent, stringTrimMethod); var assignLocalVariable = localSourceValueVariable.AssignTo(currentTrimmed); var isNumericTest = GetIsNumericTest(localSourceValueVariable); var sourceNumericValueVariableName = enumTypeName + underlyingEnumType.Name + "Value"; - var sourceNumericValueVariable = Expression.Variable(underlyingEnumType, sourceNumericValueVariableName); + var sourceNumericValueVariable = Variable(underlyingEnumType, sourceNumericValueVariableName); var parsedString = GetStringParseCall(localSourceValueVariable, underlyingEnumType); var assignNumericVariable = sourceNumericValueVariable.AssignTo(parsedString); @@ -135,7 +146,7 @@ private static Expression GetFlagsEnumConversion( out var enumValuesVariable, out var assignEnumValues); - var numericValuePopulationBlock = Expression.Block( + var numericValuePopulationBlock = Block( new[] { enumValuesVariable }, assignNumericVariable, assignEnumValues, @@ -146,24 +157,24 @@ private static Expression GetFlagsEnumConversion( underlyingTypeDefault, nonNullableTargetEnumType); - var assignParsedEnumValue = Expression.OrAssign(enumValueVariable, stringValueConversion); + var assignParsedEnumValue = OrAssign(enumValueVariable, stringValueConversion); - var assignValidValuesIfPossible = Expression.IfThenElse( + var assignValidValuesIfPossible = IfThenElse( isNumericTest, numericValuePopulationBlock, assignParsedEnumValue); - var loopBody = Expression.Block( + var loopBody = Block( new[] { localSourceValueVariable, sourceNumericValueVariable }, ifNotMoveNextBreak, assignLocalVariable, assignValidValuesIfPossible); - var populationBlock = Expression.Block( + var populationBlock = Block( new[] { sourceValuesVariable, enumValueVariable }, assignEnumValue, assignSourceValues, - Expression.Loop(loopBody, loopBreakTarget), + Loop(loopBody, loopBreakTarget), enumValueVariable.GetConversionTo(fallbackValue.Type)); return populationBlock; @@ -182,11 +193,11 @@ private static Expression GetNumericToFlagsEnumConversion( { var underlyingEnumType = enumValueVariable.Type; - var sourceValueVariable = Expression.Variable(underlyingEnumType, enumTypeName + "Source"); + var sourceValueVariable = Variable(underlyingEnumType, enumTypeName + "Source"); if (sourceValue.Type != underlyingEnumType) { - sourceValue = Expression.Convert(sourceValue, underlyingEnumType); + sourceValue = Convert(sourceValue, underlyingEnumType); } var assignSourceVariable = sourceValueVariable.AssignTo(sourceValue); @@ -199,7 +210,7 @@ private static Expression GetNumericToFlagsEnumConversion( out var enumValuesVariable, out var assignEnumValues); - var populationBlock = Expression.Block( + var populationBlock = Block( new[] { sourceValueVariable, enumValueVariable, enumValuesVariable }, assignSourceVariable, assignEnumValue, @@ -227,28 +238,28 @@ private static Expression GetNumericToFlagsEnumPopulationLoop( var ifNotMoveNextBreak = GetLoopExitCheck(enumValuesVariable, out var loopBreakTarget); - var localEnumValueVariable = Expression.Variable(underlyingEnumType, enumTypeName); - var enumeratorCurrent = Expression.Property(enumValuesVariable, "Current"); + var localEnumValueVariable = Variable(underlyingEnumType, enumTypeName); + var enumeratorCurrent = Property(enumValuesVariable, "Current"); var assignLocalVariable = localEnumValueVariable.AssignTo(enumeratorCurrent); - var localVariableAndSourceValue = Expression.And(localEnumValueVariable, sourceValueVariable); - var andResultEqualsEnumValue = Expression.Equal(localVariableAndSourceValue, localEnumValueVariable); + var localVariableAndSourceValue = And(localEnumValueVariable, sourceValueVariable); + var andResultEqualsEnumValue = Equal(localVariableAndSourceValue, localEnumValueVariable); - var ifAndResultMatchesAssign = Expression.IfThen( + var ifAndResultMatchesAssign = IfThen( andResultEqualsEnumValue, - Expression.OrAssign(enumValueVariable, localEnumValueVariable)); + OrAssign(enumValueVariable, localEnumValueVariable)); - var loopBody = Expression.Block( + var loopBody = Block( new[] { localEnumValueVariable }, ifNotMoveNextBreak, assignLocalVariable, ifAndResultMatchesAssign); - return Expression.Loop(loopBody, loopBreakTarget); + return Loop(loopBody, loopBreakTarget); } private static ParameterExpression GetEnumValuesVariable(string enumTypeName, Type elementType) - => Expression.Variable(typeof(IEnumerator<>).MakeGenericType(elementType), enumTypeName + "Values"); + => Variable(typeof(IEnumerator<>).MakeGenericType(elementType), enumTypeName + "Values"); private static Expression GetEnumValuesConstant(Type enumType, Type underlyingType) { @@ -280,7 +291,7 @@ private static Expression GetValuesEnumeratorAssignment( ? enumeratedValues.Type : typeof(IEnumerable<>).MakeGenericType(enumeratedValues.Type.GetEnumerableElementType()); - var getValuesEnumeratorCall = Expression.Call( + var getValuesEnumeratorCall = Call( enumeratedValues, enumerableType.GetPublicInstanceMethod("GetEnumerator")); @@ -291,18 +302,18 @@ private static Expression GetLoopExitCheck( Expression valuesEnumerator, out LabelTarget loopBreakTarget) { - var enumeratorMoveNext = Expression.Call( + var enumeratorMoveNext = Call( valuesEnumerator, typeof(IEnumerator).GetPublicInstanceMethod("MoveNext")); - loopBreakTarget = Expression.Label(); + loopBreakTarget = Label(); - return Expression.IfThen(Expression.Not(enumeratorMoveNext), Expression.Break(loopBreakTarget)); + return IfThen(Not(enumeratorMoveNext), Break(loopBreakTarget)); } private static Expression GetIsNumericTest(Expression stringValue) { - return Expression.Call( + return Call( typeof(char).GetPublicStaticMethod("IsDigit", typeof(string), typeof(int)), stringValue, ToNumericConverter.Zero); @@ -310,7 +321,7 @@ private static Expression GetIsNumericTest(Expression stringValue) public static Expression GetStringParseCall(Expression sourceValue, Type underlyingEnumType) { - return Expression.Call( + return Call( underlyingEnumType.GetPublicStaticMethod("Parse", typeof(string)), sourceValue); } @@ -336,7 +347,7 @@ private static Expression GetStringToEnumConversion( return targetEnumValues.Reverse().Aggregate( fallbackValue, - (valueSoFar, enumValue) => Expression.Condition( + (valueSoFar, enumValue) => Condition( sourceValue.GetCaseInsensitiveEquals(enumValue.Member.Name.ToConstantExpression()), enumValue.GetConversionTo(fallbackValue.Type), valueSoFar)); @@ -352,7 +363,7 @@ private static Expression GetStringToEnumValueConversion( return enumValues.Reverse().Aggregate( fallbackValue, - (valueSoFar, enumValue) => Expression.Condition( + (valueSoFar, enumValue) => Condition( sourceValue.GetCaseInsensitiveEquals(enumValue.ToString().ToConstantExpression()), ((TResult)enumValue).ToConstantExpression(fallbackValue.Type), valueSoFar)); @@ -410,8 +421,8 @@ private Expression GetEnumToEnumConversion( return valueSoFar; } - return Expression.Condition( - Expression.Equal(sourceValue, enumData.SourceValue.GetConversionTo(sourceValue.Type)), + return Condition( + Equal(sourceValue, enumData.SourceValue.GetConversionTo(sourceValue.Type)), enumData.PairedValue.Value.GetConversionTo(fallbackValue.Type), valueSoFar); }); @@ -420,20 +431,33 @@ private Expression GetEnumToEnumConversion( } private static IList GetEnumValues(Type enumType) - => enumType.GetPublicStaticFields().Project(f => Expression.Field(null, f)).ToList(); + => enumType.GetPublicStaticFields().Project(f => Field(null, f)).ToList(); private static Expression GetNumericToEnumConversion( Expression sourceValue, Expression fallbackValue, Type nonNullableSourceType, - Type nonNullableTargetEnumType) + Type nonNullableTargetEnumType, + bool useSingleStatement) { + if (!useSingleStatement) + { + return GetEnumMappingSwitchBlock( + sourceValue, + fallbackValue, + nonNullableTargetEnumType, + (enumValue, enumNumericType) => new[] { ChangeType(enumValue, enumNumericType) }, + (switchValue, enumNumericType) => switchValue.GetConversionTo(enumNumericType)); + } + + var targetEnumType = fallbackValue.Type; var underlyingEnumType = Enum.GetUnderlyingType(nonNullableTargetEnumType); var convertedNumericValue = sourceValue.GetConversionTo(underlyingEnumType); + var validEnumValues = GetEnumValuesConstant(targetEnumType, underlyingEnumType); - var validValueOrFallback = Expression.Condition( - GetIsValidEnumValueCheck(nonNullableTargetEnumType, convertedNumericValue), - sourceValue.GetConversionTo(nonNullableTargetEnumType).GetConversionTo(fallbackValue.Type), + var validValueOrFallback = Condition( + GetIsValidEnumValueCheck(convertedNumericValue, validEnumValues), + sourceValue.GetConversionTo(nonNullableTargetEnumType).GetConversionTo(targetEnumType), fallbackValue); if (sourceValue.Type == nonNullableSourceType) @@ -441,7 +465,7 @@ private static Expression GetNumericToEnumConversion( return validValueOrFallback; } - var nonNullValidValueOrFallback = Expression.Condition( + var nonNullValidValueOrFallback = Condition( sourceValue.GetIsNotDefaultComparison(), validValueOrFallback, fallbackValue); @@ -449,32 +473,103 @@ private static Expression GetNumericToEnumConversion( return nonNullValidValueOrFallback; } - private static Expression GetIsValidEnumValueCheck( - Type enumType, - Expression value, - Expression validEnumValues = null) + private static Expression GetEnumMappingSwitchBlock( + Expression sourceValue, + Expression fallbackValue, + Type nonNullableTargetEnumType, + Func caseTestValuesFactory, + Func switchValueFactory = null) { - if (validEnumValues == null) + var targetEnumType = fallbackValue.Type; + var enumNumericType = Enum.GetUnderlyingType(nonNullableTargetEnumType); + + var returnTarget = Label(targetEnumType, "Return"); + + var enumSwitchCases = nonNullableTargetEnumType.GetEnumValuesArray(v => { - validEnumValues = GetEnumValuesConstant(enumType, value.Type); + var enumValue = ChangeType(v, nonNullableTargetEnumType); + + var caseTestValues = caseTestValuesFactory + .Invoke(v, enumNumericType) + .ProjectToArray(Constant); + + return SwitchCase( + Return(returnTarget, Constant(enumValue).GetConversionTo(targetEnumType)), + caseTestValues); + }); + + var mappingExpressions = new List(); + + Expression switchValue; + + if (sourceValue.Type.CanBeNull()) + { + mappingExpressions.Add(IfThen( + sourceValue.GetIsDefaultComparison(), + Return(returnTarget, fallbackValue))); + + switchValue = sourceValue.Type.IsNullableType() + ? sourceValue.GetNullableValueAccess() + : sourceValue; + } + else + { + switchValue = sourceValue; + } + + if (switchValueFactory != null) + { + switchValue = switchValueFactory.Invoke(switchValue, enumNumericType); } - var containsMethod = validEnumValues.Type.GetPublicInstanceMethod("Contains"); - var containsCall = Expression.Call(validEnumValues, containsMethod, value); + mappingExpressions.Add(Switch(switchValue, enumSwitchCases)); + mappingExpressions.Add(Label(returnTarget, fallbackValue)); - return containsCall; + return Block(mappingExpressions); } + private static Expression GetIsValidEnumValueCheck(Expression value, Expression validEnumValues) + => Call(validEnumValues, validEnumValues.Type.GetPublicInstanceMethod("Contains"), value); + private static Expression GetStringValueConversion( Expression sourceValue, Expression fallbackValue, - Type nonNullableTargetEnumType) + Type nonNullableTargetEnumType, + bool useSingleStatement) { + if (!useSingleStatement && + sourceValue.Type.GetNonNullableType() == typeof(char)) + { + return GetEnumMappingSwitchBlock( + sourceValue, + fallbackValue, + nonNullableTargetEnumType, + (enumValue, enumNumericType) => new object[] + { + ChangeType(enumValue, enumNumericType).ToString()[0] + }); + } + if (sourceValue.Type != typeof(string)) { sourceValue = ToStringConverter.GetConversion(sourceValue); } + if (!useSingleStatement) + { + return GetEnumMappingSwitchBlock( + sourceValue, + fallbackValue, + nonNullableTargetEnumType, + (enumValue, enumNumericType) => new object[] + { + ChangeType(enumValue, enumNumericType).ToString(), + enumValue.ToString().ToUpperInvariant() + }, + (switchValue, _) => Call(switchValue, typeof(string) + .GetPublicInstanceMethod("ToUpperInvariant"))); + } + var underlyingEnumType = Enum.GetUnderlyingType(nonNullableTargetEnumType); var isNumericTest = GetIsNumericTest(sourceValue); @@ -490,12 +585,12 @@ private static Expression GetStringValueConversion( fallbackValue, nonNullableTargetEnumType); - var numericOrNameConversion = Expression.Condition( + var numericOrNameConversion = Condition( isNumericTest, numericConversion, nameMatchingConversion); - var convertedValueOrDefault = Expression.Condition( + var convertedValueOrDefault = Condition( StringExpressionExtensions.GetIsNullOrWhiteSpaceCall(sourceValue), fallbackValue, numericOrNameConversion); @@ -510,13 +605,13 @@ private static Expression GetNumericStringToEnumConversion( Type underlyingEnumType) { var validEnumValues = nonNullableTargetEnumType - .GetEnumValuesArray(v => Convert.ChangeType(v, underlyingEnumType).ToString()) + .GetEnumValuesArray(v => ChangeType(v, underlyingEnumType).ToString()) .ToConstantExpression(typeof(ICollection)); var parsedString = GetStringParseCall(sourceValue, underlyingEnumType); - var validValueOrFallback = Expression.Condition( - GetIsValidEnumValueCheck(nonNullableTargetEnumType, sourceValue, validEnumValues), + var validValueOrFallback = Condition( + GetIsValidEnumValueCheck(sourceValue, validEnumValues), parsedString.GetConversionTo(fallbackValue.Type), fallbackValue); diff --git a/AgileMapper/TypeConversion/ToFormattedStringConverter.cs b/AgileMapper/TypeConversion/ToFormattedStringConverter.cs index 052f9d6ba..d86a2d0ac 100644 --- a/AgileMapper/TypeConversion/ToFormattedStringConverter.cs +++ b/AgileMapper/TypeConversion/ToFormattedStringConverter.cs @@ -25,7 +25,8 @@ public ToFormattedStringConverter(Type sourceValueType, string formattingString) if (_toStringMethod == null) { throw new MappingConfigurationException( - "No ToString method taking a formatting string exists on type " + sourceValueType.GetFriendlyName()); + "No ToString() method taking a formatting string exists " + + "on type " + sourceValueType.GetFriendlyName()); } _sourceValueType = sourceValueType; @@ -35,7 +36,10 @@ public ToFormattedStringConverter(Type sourceValueType, string formattingString) public bool CanConvert(Type nonNullableSourceType, Type nonNullableTargetType) => (nonNullableTargetType == typeof(string)) && (_sourceValueType == nonNullableSourceType); - public Expression GetConversion(Expression sourceValue, Type targetType) + public Expression GetConversion( + Expression sourceValue, + Type targetType, + bool useSingleStatement) { if (sourceValue.Type.IsNullableType()) { diff --git a/AgileMapper/TypeConversion/ToGuidConverter.cs b/AgileMapper/TypeConversion/ToGuidConverter.cs index 348ec6aaa..9a678b569 100644 --- a/AgileMapper/TypeConversion/ToGuidConverter.cs +++ b/AgileMapper/TypeConversion/ToGuidConverter.cs @@ -22,7 +22,7 @@ public bool CanConvert(Type nonNullableSourceType, Type nonNullableTargetType) ToStringConverter.HasNativeStringRepresentation(nonNullableSourceType)); } - public Expression GetConversion(Expression sourceValue, Type targetType) + public Expression GetConversion(Expression sourceValue, Type targetType, bool useSingleStatement) { if (sourceValue.Type == typeof(Guid?)) { diff --git a/AgileMapper/TypeConversion/ToNumericConverter.cs b/AgileMapper/TypeConversion/ToNumericConverter.cs index 9915ef9a9..a3ab7fb23 100644 --- a/AgileMapper/TypeConversion/ToNumericConverter.cs +++ b/AgileMapper/TypeConversion/ToNumericConverter.cs @@ -9,13 +9,12 @@ #endif using Extensions.Internal; using NetStandardPolyfills; - using ReadableExpressions.Extensions; internal class ToNumericConverter : TryParseConverter { #region Cached Items - public new static readonly ToNumericConverter Instance = new ToNumericConverter(); + public new static readonly ToNumericConverter Instance = new(); private static readonly Type[] _coercibleNumericTypes = typeof(TNumeric).GetCoercibleNumericTypes(); @@ -45,7 +44,10 @@ protected override bool CanConvert(Type nonNullableSourceType) Constants.NumericTypes.Contains(nonNullableSourceType); } - public override Expression GetConversion(Expression sourceValue, Type targetType) + public override Expression GetConversion( + Expression sourceValue, + Type targetType, + bool useSingleStatement) { var sourceType = GetNonEnumSourceType(sourceValue); var nonNullableSourceType = sourceType.GetNonNullableType(); @@ -67,7 +69,7 @@ public override Expression GetConversion(Expression sourceValue, Type targetType return IsNumericType(nonNullableSourceType) ? GetCheckedNumericConversion(sourceValue, targetType) - : base.GetConversion(sourceValue, targetType); + : base.GetConversion(sourceValue, targetType, useSingleStatement); } private static Type GetNonEnumSourceType(Expression sourceValue) diff --git a/AgileMapper/TypeConversion/ToStringConverter.cs b/AgileMapper/TypeConversion/ToStringConverter.cs index 2dbe76ac9..2e5cf2482 100644 --- a/AgileMapper/TypeConversion/ToStringConverter.cs +++ b/AgileMapper/TypeConversion/ToStringConverter.cs @@ -3,16 +3,15 @@ using System; using System.Globalization; using System.Linq; - using System.Reflection; - using Extensions; - using Extensions.Internal; - using NetStandardPolyfills; - using ReadableExpressions.Extensions; #if NET35 using Microsoft.Scripting.Ast; #else using System.Linq.Expressions; #endif + using System.Reflection; + using Extensions; + using Extensions.Internal; + using NetStandardPolyfills; internal struct ToStringConverter : IValueConverter { @@ -36,7 +35,7 @@ private static bool HasToStringOperator(Type nonNullableSourceType, out MethodIn return operatorMethod != null; } - public Expression GetConversion(Expression sourceValue, Type targetType) + public Expression GetConversion(Expression sourceValue, Type targetType, bool useSingleStatement) { // Target type is always 'string': return GetConversion(sourceValue); diff --git a/AgileMapper/TypeConversion/TryParseConverter.cs b/AgileMapper/TypeConversion/TryParseConverter.cs index f9a19f9e4..3facab1cf 100644 --- a/AgileMapper/TypeConversion/TryParseConverter.cs +++ b/AgileMapper/TypeConversion/TryParseConverter.cs @@ -1,19 +1,19 @@ namespace AgileObjects.AgileMapper.TypeConversion { using System; - using System.Reflection; - using Extensions.Internal; - using NetStandardPolyfills; - using ReadableExpressions.Extensions; #if NET35 using Microsoft.Scripting.Ast; #else using System.Linq.Expressions; #endif + using System.Reflection; + using Extensions.Internal; + using NetStandardPolyfills; + using ReadableExpressions.Extensions; internal class TryParseConverter : IValueConverter { - public static readonly TryParseConverter Instance = new TryParseConverter(); + public static readonly TryParseConverter Instance = new(); public virtual bool CanConvert(Type nonNullableSourceType, Type nonNullableTargetType) { @@ -21,7 +21,10 @@ public virtual bool CanConvert(Type nonNullableSourceType, Type nonNullableTarge ToStringConverter.HasNativeStringRepresentation(nonNullableSourceType); } - public virtual Expression GetConversion(Expression sourceValue, Type targetType) + public virtual Expression GetConversion( + Expression sourceValue, + Type targetType, + bool useSingleStatement) { var nonNullableTargetType = targetType.GetNonNullableType(); var tryParseMethod = GetTryParseMethod(nonNullableTargetType); @@ -68,7 +71,7 @@ protected static MethodInfo GetTryParseMethod(Type nonNullableTargetType) internal class TryParseConverter : TryParseConverter { - public new static readonly TryParseConverter Instance = new TryParseConverter(); + public new static readonly TryParseConverter Instance = new(); private readonly Type _nonNullableTargetType; private readonly Type _nullableTargetType; @@ -93,7 +96,10 @@ protected virtual bool CanConvert(Type nonNullableSourceType) ToStringConverter.HasNativeStringRepresentation(nonNullableSourceType); } - public override Expression GetConversion(Expression sourceValue, Type targetType) + public override Expression GetConversion( + Expression sourceValue, + Type targetType, + bool useSingleStatement) { if (sourceValue.Type == _nullableTargetType) { diff --git a/AgileMapper/TypeConversion/TypeConversionExtensions.cs b/AgileMapper/TypeConversion/TypeConversionExtensions.cs index 5425f53b1..6f43ac549 100644 --- a/AgileMapper/TypeConversion/TypeConversionExtensions.cs +++ b/AgileMapper/TypeConversion/TypeConversionExtensions.cs @@ -13,7 +13,7 @@ using Extensions; using Extensions.Internal; using Members; - using Members.MemberExtensions; + using Members.Extensions; using NetStandardPolyfills; using ObjectPopulation; @@ -48,8 +48,14 @@ public static Expression GetValueConversionOrCreation( return mapperData.GetConversionOrCreationExpression(value, targetType, valueFactories); } - public static Expression GetValueConversion(this IMemberMapperData mapperData, Expression value, Type targetType) - => mapperData.MapperContext.GetValueConversion(value, targetType); + public static Expression GetValueConversion( + this TContext context, + Expression value, + Type targetType) + where TContext : IMapperContextOwner, IRuleSetOwner + { + return context.MapperContext.ValueConverters.GetConversion(value, targetType, context.RuleSet); + } private static bool HasConfiguredSimpleTypeValueFactories(this IMapperContextOwner mapperContextOwner) => mapperContextOwner.MapperContext.UserConfigurations.HasSimpleTypeValueFactories; diff --git a/AgileMapper/Validation/EnumMappingMismatchFinder.cs b/AgileMapper/Validation/EnumMappingMismatchFinder.cs index 668de530b..9bfb6a98f 100644 --- a/AgileMapper/Validation/EnumMappingMismatchFinder.cs +++ b/AgileMapper/Validation/EnumMappingMismatchFinder.cs @@ -13,9 +13,9 @@ using Extensions; using Extensions.Internal; using Members; + using Members.Extensions; using NetStandardPolyfills; using ObjectPopulation; - using ReadableExpressions.Extensions; internal class EnumMappingMismatchFinder : ExpressionVisitor { @@ -51,7 +51,7 @@ public static ICollection FindMismatches(ObjectMapperDat return mismatchSets; } - public static Expression Process(Expression mapping, ObjectMapperData mapperData) + public static LambdaExpression Process(LambdaExpression mapping, ObjectMapperData mapperData) { var targetMemberDatas = GetAllTargetMemberDatas(mapperData); diff --git a/AgileMapper/Validation/EnumMappingMismatchSet.cs b/AgileMapper/Validation/EnumMappingMismatchSet.cs index 30f28a589..719f02de1 100644 --- a/AgileMapper/Validation/EnumMappingMismatchSet.cs +++ b/AgileMapper/Validation/EnumMappingMismatchSet.cs @@ -12,6 +12,7 @@ using Extensions; using Extensions.Internal; using Members; + using Members.Extensions; using NetStandardPolyfills; using ReadableExpressions; @@ -20,7 +21,7 @@ internal class EnumMappingMismatchSet public static readonly IEqualityComparer Comparer = default(MismatchSetComparer); private static readonly EnumMappingMismatchSet _emptySet = - new EnumMappingMismatchSet(Enumerable.EmptyArray); + new (Enumerable.EmptyArray); private readonly IList _mappingMismatches; private Expression _warning; diff --git a/AgileMapper/Validation/MappingValidator.cs b/AgileMapper/Validation/MappingValidator.cs index 89e9785f9..745408335 100644 --- a/AgileMapper/Validation/MappingValidator.cs +++ b/AgileMapper/Validation/MappingValidator.cs @@ -8,6 +8,7 @@ using Extensions; using Extensions.Internal; using Members; + using Members.Extensions; using NetStandardPolyfills; using ObjectPopulation; using ReadableExpressions.Extensions; @@ -24,10 +25,8 @@ public static void Validate(Mapper mapper) VerifyMappingPlanIsComplete(GetAllMapperDatas(rootMapperDatas)); } - public static void Validate(ObjectMapperData mapperData) - { - VerifyMappingPlanIsComplete(GetAllMapperDatas(new[] { mapperData })); - } + public static void Validate(ObjectMapperData mapperData) + => VerifyMappingPlanIsComplete(GetAllMapperDatas(new[] { mapperData })); public static void Validate(MappingConfigInfo configInfo) { diff --git a/Directory.Build.props b/Directory.Build.props index 9fed18da9..726688721 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,7 @@  + latest AgileObjects Ltd AgileObjects.AgileMapper Steve Wilkes @@ -11,9 +12,6 @@ true git https://github.com/AgileObjects/AgileMapper - 1.8.0 - 1.8.0.0 - 1.8.0.0 \ No newline at end of file diff --git a/README.md b/README.md index f59ea4b4f..a99dc7bc7 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # AgileMapper [![NuGet version](https://badge.fury.io/nu/AgileObjects.AgileMapper.svg)](https://badge.fury.io/nu/AgileObjects.AgileMapper) -[![Build status](https://ci.appveyor.com/api/projects/status/c1jlvkfjej62p8da?svg=true)](https://ci.appveyor.com/project/SteveWilkes/agilemapper) -AgileMapper is a zero-configuration, [highly-configurable](https://agilemapper.readthedocs.io/configuration), unopinionated object -mapper with [viewable execution plans](https://agilemapper.readthedocs.io/Using-Execution-Plans). +AgileMapper is a zero-configuration, [highly-configurable](https://agilemapper.readthedocs.io/configuration), +unopinionated object mapper with execution plans you can [view](https://agilemapper.readthedocs.io/Using-Execution-Plans), +or [generate and build](https://agilemapper.readthedocs.io/mapper-generation) into your source code. It flattens, unflattens, deep clones, [merges](https://agilemapper.readthedocs.io/Performing-Merges), -[updates](https://agilemapper.readthedocs.io/Performing-Updates) and [projects queries](https://agilemapper.readthedocs.io/query-projection/) +[updates](https://agilemapper.readthedocs.io/Performing-Updates) and [projects queries](https://agilemapper.readthedocs.io/query-projection) via [extension methods](https://agilemapper.readthedocs.io/Mapping-Extension-Methods), or a [static or instance](https://agilemapper.readthedocs.io/Static-vs-Instance-Mappers) API. It targets .NET 3.5+ and [.NET Standard 1.0+](https://docs.microsoft.com/en-us/dotnet/articles/standard/library). @@ -38,6 +38,7 @@ Mapper.Map(customerViewModel).Over(customer); Mapper.Map(customerOne).OnTo(customerTwo); ``` -It's [available via NuGet](https://www.nuget.org/packages/AgileObjects.AgileMapper) and licensed with the -[MIT licence](https://github.com/agileobjects/AgileMapper/blob/master/LICENCE.md). Check out -[the documentation](https://agilemapper.readthedocs.io) for more! +It's [available via NuGet](https://www.nuget.org/packages/AgileObjects.AgileMapper), with code +generation performed by [this extension](https://www.nuget.org/packages/AgileObjects.AgileMapper.Buildable), +both licensed with the [MIT licence](https://github.com/agileobjects/AgileMapper/blob/master/LICENCE.md). +Check out [the documentation](https://agilemapper.readthedocs.io) for more! diff --git a/docs/src/Building-Mappers.md b/docs/src/Building-Mappers.md new file mode 100644 index 000000000..e69de29bb diff --git a/docs/src/configuration/Classes.md b/docs/src/configuration/Classes.md index 282b0495e..d85b5dd89 100644 --- a/docs/src/configuration/Classes.md +++ b/docs/src/configuration/Classes.md @@ -11,7 +11,7 @@ public class ProductMappingConfiguration : MapperConfiguration { protected override void Configure() { - // Configure default Mapper ProductDto -> Productmapping: + // Configure default Mapper ProductDto -> Product mapping: WhenMapping .From() .To() diff --git a/docs/src/css/styles.css b/docs/src/css/styles.css deleted file mode 100644 index 452233b07..000000000 --- a/docs/src/css/styles.css +++ /dev/null @@ -1,62 +0,0 @@ -body { - font: 400 11pt 'Segoe UI', Calibri, Arial, sans-serif !important; -} - -h1, h2, h3, h4, input[type=submit] { - font-family: 'Segoe UI Light', Calibri, Arial, sans-serif !important; - margin: 0 0 .5em; -} - -h1 { - font-size: 2.5em; -} - -h2 { - font-size: 2em; -} - -h3 { - font-size: 1.6em; -} - -h4 { - font-size: 1.2em; - margin-left: .7em; -} - -p code, li code { - border: none; - padding: 2px 0; - font-size: 11pt; - color: black; -} - -pre code { - font-size: 11pt; -} - -span.caption-text { - color: #dcdcdc; - background: #1e1e1e; -} - -p a code { - text-decoration: underline; -} - -.wy-menu-vertical li.current a { - color: #1e1e1e; -} - -li.current { - border-top: 1px solid #010101; - border-bottom: 1px solid #010101; -} - -.hljs-type, .hljs-keyword, .hljs-title, .hljs-meta-string, .hljs-meta { - font-weight: normal !important; -} - -.hljs-meta { - color: #4EC9B0; -} diff --git a/docs/src/css/styles.min.css b/docs/src/css/styles.min.css deleted file mode 100644 index 1ff85e603..000000000 --- a/docs/src/css/styles.min.css +++ /dev/null @@ -1 +0,0 @@ -body{font:400 11pt 'Segoe UI',Calibri,Arial,sans-serif!important}h1,h2,h3,h4,input[type=submit]{font-family:'Segoe UI Light',Calibri,Arial,sans-serif!important;margin:0 0 .5em}h1{font-size:2.5em}h2{font-size:2em}h3{font-size:1.6em}h4{font-size:1.2em;margin-left:.7em}li code,p code,pre code{font-size:11pt}li code,p code{border:none;padding:2px 0;color:#000}span.caption-text{color:#dcdcdc;background:#1e1e1e}p a code{text-decoration:underline}.wy-menu-vertical li.current a{color:#1e1e1e}li.current{border-top:1px solid #010101;border-bottom:1px solid #010101}.hljs-keyword,.hljs-meta,.hljs-meta-string,.hljs-title,.hljs-type{font-weight:400!important}.hljs-meta{color:#4EC9B0} \ No newline at end of file diff --git a/docs/src/index.md b/docs/src/index.md index 09769ee86..47e5ed3ea 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,12 +1,22 @@ ## Overview -AgileMapper is a zero-configuration, [highly-configurable](/configuration) object-object mapper with [viewable execution plans](/Using-Execution-Plans), targeting [.NET Standard 1.0+](https://docs.microsoft.com/en-us/dotnet/articles/standard/library) and .NET 3.5+. It performs [query projections](/query-projection), object creation, deep clones, id-aware [updates](/Performing-Updates) and [merges](/Performing-Merges), and can be used via [extension methods](/Mapping-Extension-Methods), or a [static or instance](/Static-vs-Instance-Mappers) API. - -Mapping functions are created and cached the first time two types are mapped - no up-front configuration is necessary. You can [cache up-front](/Using-Execution-Plans) if you prefer, though. - -[Available via NuGet](https://www.nuget.org/packages/AgileObjects.AgileMapper) and licensed with the [MIT licence](https://github.com/agileobjects/AgileMapper/blob/master/LICENCE.md), you can install it via the [package manager console](https://docs.nuget.org/consume/package-manager-console): - - PM> Install-Package AgileObjects.AgileMapper +AgileMapper is a zero-configuration, [highly-configurable](/configuration), unopinionated object +mapper with execution plans you can [view](/Using-Execution-Plans), or +[generate and build](/mapper-generation) into your source code. It flattens, unflattens, deep clones, +[merges](/Performing-Merges), [updates](/Performing-Updates) and [projects queries](/query-projection) +via [extension methods](/Mapping-Extension-Methods), or a [static or instance](/Static-vs-Instance-Mappers) +API. It targets .NET 3.5+ and [.NET Standard 1.0+](https://docs.microsoft.com/en-us/dotnet/articles/standard/library). + +Mapping functions are created and cached the first time two types are mapped - no up-front +configuration is necessary. You can [cache up-front](/Using-Execution-Plans) if you prefer, though. + +[Available via NuGet](https://www.nuget.org/packages/AgileObjects.AgileMapper) and licensed with the +[MIT licence](https://github.com/agileobjects/AgileMapper/blob/master/LICENCE.md), you can install it +via the [package manager console](https://docs.nuget.org/consume/package-manager-console) with: + +```shell +PM> Install-Package AgileObjects.AgileMapper +``` [![NuGet version](https://badge.fury.io/nu/AgileObjects.AgileMapper.svg)](https://badge.fury.io/nu/AgileObjects.AgileMapper) diff --git a/docs/src/mapper-generation/Configuration.md b/docs/src/mapper-generation/Configuration.md new file mode 100644 index 000000000..91c71d681 --- /dev/null +++ b/docs/src/mapper-generation/Configuration.md @@ -0,0 +1,16 @@ +Mapper source code generation can be configured in the following ways. + +## Change the Output Project + +To output your mappers to a different project, add the following to +[your mapper configuration](quickstart) project: + +```xml + + [PathToTargetCsProjFile] + +``` + +Where `PathToTargetCsProjFile` is the fully-qualified or relative path to the `.csproj` file to which +mappers should be added. + diff --git a/docs/src/mapper-generation/Quickstart.md b/docs/src/mapper-generation/Quickstart.md new file mode 100644 index 000000000..d17cd44d4 --- /dev/null +++ b/docs/src/mapper-generation/Quickstart.md @@ -0,0 +1,58 @@ +## Add the Package + +Add the AgileMapper.Buildable package to the project which will contain your configuration (see +below), and generate your mappers when built: + +```shell +PM> Install-Package AgileObjects.AgileMapper.Buildable -Pre +``` +The `-Pre` flag is required as AgileMapper.Buildable is currently in preview. + +## Add Configuration + +To specify which mapper source code should be generated, add one or more +[configuration classes](../configuration/classes) to a project, derived from AgileMapper.Buildable's +`BuildableMapperConfiguration` class: + +```cs +public class ProductMappingConfiguration : BuildableMapperConfiguration +{ + protected override void Configure() + { + // Configure default Mapper ProductDto -> Product mapping: + WhenMapping + .From() + .To() + .Map((dto, p) => dto.Spec) + .To(p => p.Specification) + .And + .Ignore(p => p.Price, p => p.CatNum); + + // Generate all Product -> ProductDto mappers: + GetPlansFor().To(); + } +} +``` + +AgileMapper.Buildable configuration classes work the same as +[AgileMapper configuration classes](../configuration/classes), but instead of configuring mappers +built at runtime, they configure mappers generated at build time. + +AgileMapper.Buildable auto-discovers its configuration, and does not need it to be registered using +the `Mapper.WhenMapping.UseConfigurations.From*` methods. + +## Generate Mappers + +When the project is built, it will generate the following source code based on your configuration: + +- One instance-scoped mapper per configured source type +- A static `Mapper` class +- A set of mapping extension methods. + +These files are output to a `Mappers` folder and namespace at the root of the project. The static +mapper and extension methods use the instance mappers to perform mappings. + +The generated static Mapper and extension methods have the same signatures as AgileMapper's +equivalent classes, so you can switch from AgileMapper's mapping to your generated mappers simply by +changing the `using AgileObjects.AgileMapper;` namespace import to +`using [YourProject.Namespace].Mappers;`. \ No newline at end of file diff --git a/docs/src/mapper-generation/index.md b/docs/src/mapper-generation/index.md new file mode 100644 index 000000000..b17d8ee0d --- /dev/null +++ b/docs/src/mapper-generation/index.md @@ -0,0 +1,19 @@ +AgileMapper.Buildable is an AgileMapper extension which uses a custom MSBuild target to generate +mapper source code at build time. This provides the best mapping performance, and enables you to step +into and debug your mappers at runtime. + +It targets .NET 4.6.1+ and [.NET Standard 2.0+](https://docs.microsoft.com/en-us/dotnet/articles/standard/library), +and supports [dotnet build](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-build) and +[MSBuild](https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild), +[SDK](https://docs.microsoft.com/en-us/dotnet/core/project-sdk/overview) and non-SDK projects. + +[Available via NuGet](https://www.nuget.org/packages/AgileObjects.AgileMapper.Buildable) and licensed +with the [MIT licence](https://github.com/agileobjects/AgileMapper/blob/master/LICENCE.md), you can +install it via the [package manager console](https://docs.nuget.org/consume/package-manager-console) +with: + +```shell +PM> Install-Package AgileObjects.AgileMapper.Buildable -Pre +``` + +The `-Pre` flag is required as AgileMapper.Buildable is currently in preview. \ No newline at end of file diff --git a/docs/src/scripts/docs.js b/docs/src/scripts/docs.js deleted file mode 100644 index 8261aa084..000000000 --- a/docs/src/scripts/docs.js +++ /dev/null @@ -1,25 +0,0 @@ -$(function () { - var hlCode = document.querySelectorAll('pre code.cs'), - i, l, - hlLength = hlCode.length, - mapperRegex = /\bMapper\b/g, - typeRegex = /(new<\/span>\W+|class<\/span> |public<\/span>\W+|: |<)([A-Z][^& \(\[\]]+)( |{|\(|\[\]>|>)/g, - genericTypeRegex = /(I{0,1}Dictionary|IEnumerable|IReadOnlyCollection|I{0,1}Collection|I{0,1}List)</g, - observer = new MutationObserver(function (mutations) { - for (i = 0, l = mutations.length; i < l; ++i) { - var mutation = mutations[i]; - if (mutation.attributeName === 'class') { - var innerHTML = mutation.target.innerHTML - .replace(mapperRegex, 'Mapper') - .replace(typeRegex, '$1$2$3') - .replace(genericTypeRegex, '$1<'); - mutation.target.innerHTML = innerHTML; - } - } - }), - config = { attributes: true }; - - for (i = 0; i < hlLength; ++i) { - observer.observe(hlCode[i], config); - } -}); \ No newline at end of file diff --git a/docs/src/scripts/docs.min.js b/docs/src/scripts/docs.min.js deleted file mode 100644 index 4963897cb..000000000 --- a/docs/src/scripts/docs.min.js +++ /dev/null @@ -1 +0,0 @@ -$(function () { var e, a, s = document.querySelectorAll("pre code.cs"), t = s.length, l = /\bMapper\b/g, n = /(\[|new<\/span>\W+|class<\/span> |public<\/span>\W+|: |<)([A-Z][^& \(\[\]]+)(\]| |{|\(|\[\]>|>)/g, r = /(I{0,1}Dictionary|IEnumerable|IReadOnlyCollection|I{0,1}Collection|I{0,1}List)</g, p = new MutationObserver(function (s) { for (e = 0, a = s.length; e < a; ++e) { var t = s[e]; if ("class" === t.attributeName) { var p = t.target.innerHTML.replace(l, 'Mapper').replace(n, '$1$2$3').replace(r, '$1<'); t.target.innerHTML = p } } }), c = { attributes: !0 }; for (e = 0; e < t; ++e)p.observe(s[e], c) }); \ No newline at end of file diff --git a/docs/src/scripts/dox-cls.js b/docs/src/scripts/dox-cls.js new file mode 100644 index 000000000..bba0fd2ce --- /dev/null +++ b/docs/src/scripts/dox-cls.js @@ -0,0 +1 @@ +window['dox-cls'] = 'Mapper'; \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 3a1b305f7..7a4e37cfb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,5 +1,5 @@ site_name: AgileMapper -site_description: 'AgileMapper: A zero-configuration, highly-configurable object-object mapper with viewable execution plans. Projects queries, transforms, deep clones, updates and merges via extension methods, or a static or instance API. Targets .NET Standard 1.0+ and .NET 3.5+' +site_description: 'AgileMapper: A zero-configuration, highly-configurable, unopinionated object-object mapper with viewable execution plans. Flattens, unflattens, deep clones, merges, updates and projects queries via extension methods, or a static or instance API. Targets .NET 3.5+ and .NET Standard 1.0+.' site_author: Steve Wilkes repo_url: https://github.com/agileobjects/AgileMapper @@ -8,10 +8,11 @@ site_dir: 'docs/site' extra_css: - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/vs2015.min.css - - css/styles.min.css + - https://agileobjects.co.uk/assets/css/docs-styles.min.css extra_javascript: - - scripts/docs.min.js + - assets/scripts/dox-cls.js + - https://agileobjects.co.uk/assets/js/ao-docs.min.js nav: - General Use: @@ -41,6 +42,10 @@ nav: - Recursion: query-projection/Recursive-Relationships.md - Join entities: query-projection/Join-Entities.md - Entity Framework: query-projection/Entity-Framework.md + - Source Code Generation: + - Overview: mapper-generation/index.md + - Quickstart: mapper-generation/Quickstart.md + - Configuration: mapper-generation/Configuration.md - Configuration: - Overview: configuration/index.md - Configuring inline: configuration/Inline.md