├── .config └── dotnet-tools.json ├── .github └── workflows │ └── dotnet-buildandtest.yml ├── .gitignore ├── LICENSE ├── README.md └── src ├── .editorconfig ├── Benchmark ├── Benchmark.csproj ├── Benchmarks │ ├── Config.cs │ ├── TestAll.cs │ ├── TestComplexTypes.cs │ └── TestSimpleTypes.cs ├── Classes │ ├── Customer.cs │ └── Foo.cs ├── CustomerMapper.g.cs ├── CustomerMapper.tt ├── FooMapper.g.cs ├── FooMapper.tt ├── Program.cs └── TestAdaptHelper.cs ├── Directory.Build.props ├── ExpressionDebugger.Console ├── ExpressionDebugger.Console.csproj └── Program.cs ├── ExpressionDebugger.Tests ├── DebugInfoInjectorTest.cs └── ExpressionDebugger.Tests.csproj ├── ExpressionDebugger.sln ├── ExpressionDebugger ├── ExpressionCompilationOptions.cs ├── ExpressionCompiler.cs ├── ExpressionDebugger.csproj ├── ExpressionDebugger.snk └── ExpressionDebuggerExtensions.cs ├── ExpressionTranslator ├── ExpressionDefinitions.cs ├── ExpressionTranslator.cs ├── ExpressionTranslator.csproj ├── ExpressionTranslator.snk ├── ExpressionTranslatorExtensions.cs ├── Extensions.cs ├── PropertyDefinitions.cs ├── TypeDefinitions.cs └── icon.png ├── Mapster.Async.Tests ├── AsyncTest.cs └── Mapster.Async.Tests.csproj ├── Mapster.Async ├── Mapster.Async.csproj ├── Mapster.Async.snk ├── TypeAdapterExtensions.cs └── icon.png ├── Mapster.Core ├── Attributes │ ├── AdaptIgnoreAttribute.cs │ ├── AdaptMemberAttribute.cs │ ├── BaseAdaptAttribute.cs │ ├── GenerateMapperAttribute.cs │ ├── MapperAttribute.cs │ ├── PropertyTypeAttribute.cs │ └── UseDestinationValueAttribute.cs ├── Enums │ ├── MapType.cs │ └── MemberSide.cs ├── MapContext │ ├── MapContext.cs │ └── MapContextScope.cs ├── Mapster.Core.csproj ├── Mapster.Core.csproj.DotSettings ├── Mapster.Core.snk ├── Models │ └── Never.cs ├── Register │ ├── AdaptAttributeBuilder.cs │ ├── CodeGenerationConfig.cs │ ├── GenerateMapperAttributeBuilder.cs │ ├── ICodeGenerationRegister.cs │ ├── PropertySetting.cs │ └── PropertySettingBuilder.cs ├── Utils │ ├── Enum.cs │ ├── Extensions.cs │ ├── MapsterHelper.cs │ ├── NameHelper.cs │ └── ReferenceTuple.cs └── icon.png ├── Mapster.DependencyInjection.Tests ├── InjectionTest.cs └── Mapster.DependencyInjection.Tests.csproj ├── Mapster.DependencyInjection ├── Mapster.DependencyInjection.csproj ├── Mapster.DependencyInjection.snk ├── ServiceCollectionExtensions.cs ├── ServiceMapper.cs ├── TypeAdapterExtensions.cs └── icon.png ├── Mapster.EF6 ├── Mapster.EF6.csproj ├── Mapster.EF6.snk ├── TypeAdapterBuilderExtensions.cs ├── icon.png └── packages.config ├── Mapster.EFCore.Tests ├── DbInitializer.cs ├── EFCoreTest.cs ├── Mapster.EFCore.Tests.csproj └── Models │ ├── Course.cs │ ├── Enrollment.cs │ ├── SchoolContext.cs │ └── Student.cs ├── Mapster.EFCore ├── Mapster.EFCore.csproj ├── Mapster.EFCore.snk ├── MapsterQueryable.cs ├── TypeAdapterBuilderExtensions.cs ├── icon.png └── packages.config ├── Mapster.Immutable.Tests ├── ImmutableTest.cs └── Mapster.Immutable.Tests.csproj ├── Mapster.Immutable ├── ImmutableAdapter.cs ├── Mapster.Immutable.csproj ├── Mapster.Immutable.snk ├── TypeAdapterConfigExtensions.cs └── icon.png ├── Mapster.JsonNet.Tests ├── JsonMappingTest.cs └── Mapster.JsonNet.Tests.csproj ├── Mapster.JsonNet ├── JsonAdapter.cs ├── Mapster.JsonNet.csproj ├── Mapster.JsonNet.snk ├── TypeAdapterConfigExtensions.cs └── icon.png ├── Mapster.SourceGenerator ├── Mapster.SourceGenerator.csproj ├── Mapster.SourceGenerator.snk └── icon.png ├── Mapster.Tests ├── Classes │ ├── Address.cs │ ├── Customer.cs │ ├── Product.cs │ └── TypeTestClass.cs ├── Diagnostics │ ├── DebugInfoInjectorEx.cs │ ├── GlobalReference.cs │ └── TypeAdapterConfigExtensions.cs ├── DynamicTypeGeneratorTests.cs ├── Mapster.Tests.csproj ├── Mapster.Tests.snk ├── Properties │ └── AssemblyInfo.cs ├── WhenAddingCustomMappings.cs ├── WhenCloningConfig.cs ├── WhenCompilingConfig.cs ├── WhenConfiguringMapping.cs ├── WhenConvertingFromObjects.cs ├── WhenCreatingConfigInstance.cs ├── WhenExplicitMappingRequired.cs ├── WhenFlattening.cs ├── WhenForkingConfig.cs ├── WhenHandlingUnmappedMembers.cs ├── WhenIgnoreMapping.cs ├── WhenIgnoreWithAttribute.cs ├── WhenIgnoringConditionally.cs ├── WhenIgnoringNonMapped.cs ├── WhenIncludeDerivedClasses.cs ├── WhenMappingArrays.cs ├── WhenMappingCollections.cs ├── WhenMappingComplexClasses.cs ├── WhenMappingConditionally.cs ├── WhenMappingDerived.cs ├── WhenMappingEntityWithOnlyPrimitives.cs ├── WhenMappingEnums.cs ├── WhenMappingErrorThrown.cs ├── WhenMappingIEnumerableClass.cs ├── WhenMappingIgnoreNullValues.cs ├── WhenMappingMultipleSources.cs ├── WhenMappingNonPublicSetters.cs ├── WhenMappingNullablePrimitives.cs ├── WhenMappingPrimitives.cs ├── WhenMappingPrivateFieldsAndProperties.cs ├── WhenMappingRecordTypes.cs ├── WhenMappingStruct.cs ├── WhenMappingStructRegression.cs ├── WhenMappingToConstructor.cs ├── WhenMappingToConstructorAndPrivateSetters.cs ├── WhenMappingToInterface.cs ├── WhenMappingToTarget.cs ├── WhenMappingWithAdaptIgnoreRegression.cs ├── WhenMappingWithDictionary.cs ├── WhenMappingWithExplicitInheritance.cs ├── WhenMappingWithExtensionMethods.cs ├── WhenMappingWithFlexibleName.cs ├── WhenMappingWithGetMethod.cs ├── WhenMappingWithIReadOnlyDictionary.cs ├── WhenMappingWithImplicitInheritance.cs ├── WhenMappingWithInstance.cs ├── WhenMappingWithOpenGenerics.cs ├── WhenMappingWithParametersOnRecordsRegression.cs ├── WhenMappingWithPath.cs ├── WhenMappingWithSecondSourceObject.cs ├── WhenPassingRuntimeValue.cs ├── WhenPerformingAfterMapping.cs ├── WhenPerformingBeforeMapping.cs ├── WhenPerformingDestinationTransforms.cs ├── WhenPreserveReferences.cs ├── WhenProjecting.cs ├── WhenRegisteringAndMappingRace.cs ├── WhenRunningOnMultipleThreads.cs ├── WhenScanningForRegisters.cs ├── WhenSettingMapToTargetWith.cs ├── WhenUnflattening.cs ├── WhenUsingAttribute.cs ├── WhenUsingAttributeWithNameMatchingStrategy.cs ├── WhenUsingConverterFactory.cs ├── WhenUsingDestinationValue.cs ├── WhenUsingIMapFrom.cs ├── WhenUsingIMapFromWrong.cs ├── WhenUsingMaxDepth.cs ├── WhenUsingNonDefaultConstructor.cs ├── WhenUsingRuleBasedSetting.cs └── mock.keys ├── Mapster.Tool.Tests ├── .config │ └── dotnet-tools.json ├── Mappers │ ├── IUserMapper.cs │ └── UserMapper.cs ├── Mapster.Tool.Tests.csproj ├── TestBase.cs ├── Usings.cs └── WhenMappingWithExistingObjectAndInitProperties.cs ├── Mapster.Tool ├── ExtensionOptions.cs ├── Extensions.cs ├── MapperOptions.cs ├── Mapster.Tool.csproj ├── Mapster.Tool.snk ├── MockType.cs ├── ModelOptions.cs ├── Program.cs ├── Properties │ └── launchSettings.json └── icon.png ├── Mapster.sln ├── Mapster ├── Adapters │ ├── ArrayAdapter.cs │ ├── BaseAdapter.cs │ ├── BaseAfterMapper.cs │ ├── BaseClassAdapter.cs │ ├── ClassAdapter.cs │ ├── CollectionAdapter.cs │ ├── DelegateAdapter.cs │ ├── DictionaryAdapter.cs │ ├── EnumAdapter.cs │ ├── MultiDimensionalArrayAdapter.cs │ ├── ObjectAdapter.cs │ ├── ObjectType.cs │ ├── PrimitiveAdapter.cs │ ├── RecordTypeAdapter.cs │ └── StringAdapter.cs ├── Compile │ ├── CompileArgument.cs │ ├── CompileContext.cs │ ├── CompileException.cs │ └── PreCompileArgument.cs ├── Enums │ ├── AccessModifier.cs │ └── EnumMappingStrategy.cs ├── Extensions.cs ├── Interfaces │ ├── IAdapterBuilder.cs │ ├── IApplyable.cs │ ├── IMapFrom.cs │ ├── IMapper.cs │ ├── IRegister.cs │ └── ITypeAdapterBuilder.cs ├── Mapper.cs ├── Mapster.csproj ├── Mapster.csproj.DotSettings ├── Mapster.nuget.targets ├── Mapster.snk ├── Models │ ├── ClassMapping.cs │ ├── ClassModel.cs │ ├── FieldModel.cs │ ├── IMemberModel.cs │ ├── IMemberModelEx.cs │ ├── InvokerModel.cs │ ├── KeyValuePairModel.cs │ ├── MemberMapping.cs │ ├── ParameterModel.cs │ ├── PropertyModel.cs │ └── TypeTuple.cs ├── Properties │ └── AssemblyInfo.cs ├── Settings │ ├── DestinationTransform.cs │ ├── GetMemberName.cs │ ├── IgnoreDictionary.cs │ ├── NameMatchingStrategy.cs │ ├── SettingStore.cs │ ├── ShouldMapMember.cs │ ├── UseDestinationValue.cs │ └── ValueAccessingStrategy.cs ├── TypeAdapter.cs ├── TypeAdapterBuilder.cs ├── TypeAdapterConfig.cs ├── TypeAdapterRule.cs ├── TypeAdapterSetter.cs ├── TypeAdapterSettings.cs ├── Utils │ ├── BlockExpressionDetector.cs │ ├── ComplexExpressionVisitor.cs │ ├── CoreExtensions.cs │ ├── CustomAttributeUtil.cs │ ├── DynamicTypeGenerator.cs │ ├── ExpressionEx.cs │ ├── InterfaceDynamicMapper.cs │ ├── NullableExpressionVisitor.cs │ ├── ParameterExpressionReplacer.cs │ ├── ReflectionUtils.cs │ └── TypeAdapterConfigExtensions.cs └── icon.png ├── Pack.bat ├── Publish.bat ├── Sample.AspNetCore ├── Controllers │ └── SchoolController.cs ├── DbInitializer.cs ├── Models │ ├── Course.cs │ ├── Enrollment.cs │ ├── SchoolContext.cs │ └── Student.cs ├── NameFormatter.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Sample.AspNetCore.csproj ├── Startup.cs ├── appsettings.Development.json └── appsettings.json ├── Sample.CodeGen ├── Controllers │ └── SchoolController.cs ├── DbInitializer.cs ├── Domains │ ├── Course.cs │ ├── Enrollment.cs │ ├── SchoolContext.cs │ └── Student.cs ├── Mappers │ ├── IStudentMapper.cs │ └── StudentMapper.g.cs ├── MappingRegister.cs ├── Models │ ├── CourseAdd.g.cs │ ├── CourseDto.g.cs │ ├── CourseMapper.g.cs │ ├── CourseMerge.g.cs │ ├── CourseUpdate.g.cs │ ├── EnrollmentAdd.g.cs │ ├── EnrollmentDto.g.cs │ ├── EnrollmentMerge.g.cs │ ├── EnrollmentUpdate.g.cs │ ├── Person.cs │ ├── StudentAdd.g.cs │ ├── StudentDto.g.cs │ ├── StudentMapper.g.cs │ ├── StudentMerge.g.cs │ └── StudentUpdate.g.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Sample.CodeGen.csproj ├── Startup.cs ├── appsettings.Development.json └── appsettings.json └── TemplateTest ├── CreateMapExpressionTest.cs ├── FooTest.cs └── TemplateTest.csproj /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "mapster.tool": { 6 | "version": "8.1.0", 7 | "commands": [ 8 | "dotnet-mapster" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /.github/workflows/dotnet-buildandtest.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a .NET project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net 3 | 4 | name: Build and Test 5 | 6 | on: 7 | push: 8 | branches: [ "master", "main", "development", "**" ] 9 | pull_request: 10 | branches: [ "master", "main", "development" ] 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Setup .NET 17 | uses: actions/setup-dotnet@v3 18 | with: 19 | dotnet-version: 7.0.x 20 | - name: Show dotnet version 21 | run: | 22 | dotnet --list-sdks 23 | dotnet --list-runtimes 24 | - name: Build with dotnet 25 | run: dotnet build ./src/Mapster.sln 26 | - name: Run tests on .NET 7.0 27 | run: dotnet test --verbosity normal ./src/Mapster.sln 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Chaowlert Chaisrichalermpol, Eric Swann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # S3220: Method calls should not resolve ambiguously to overloads with "params" 4 | dotnet_diagnostic.S3220.severity = suggestion 5 | 6 | # RCS1238: Avoid nested ?: operators. 7 | dotnet_diagnostic.RCS1238.severity = suggestion 8 | 9 | # S3358: Ternary operators should not be nested 10 | dotnet_diagnostic.S3358.severity = suggestion 11 | 12 | # S125: Sections of code should not be commented out 13 | dotnet_diagnostic.S125.severity = suggestion 14 | 15 | # RCS1146: Use conditional access. 16 | dotnet_diagnostic.RCS1146.severity = suggestion 17 | -------------------------------------------------------------------------------- /src/Benchmark/Benchmark.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net6.0 6 | true 7 | **/*.g.cs 8 | 9 | 10 | 11 | True 12 | True 13 | CustomerMapper.tt 14 | 15 | 16 | True 17 | True 18 | FooMapper.tt 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | TextTemplatingFileGenerator 36 | CustomerMapper.g.cs 37 | 38 | 39 | TextTemplatingFileGenerator 40 | FooMapper.g.cs 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/Benchmark/Benchmarks/Config.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Columns; 2 | using BenchmarkDotNet.Configs; 3 | using BenchmarkDotNet.Diagnosers; 4 | using BenchmarkDotNet.Exporters; 5 | using BenchmarkDotNet.Exporters.Csv; 6 | using BenchmarkDotNet.Jobs; 7 | using BenchmarkDotNet.Loggers; 8 | 9 | namespace Benchmark.Benchmarks 10 | { 11 | public class Config : ManualConfig 12 | { 13 | public Config() 14 | { 15 | AddLogger(ConsoleLogger.Default); 16 | 17 | AddExporter(CsvExporter.Default); 18 | AddExporter(MarkdownExporter.GitHub); 19 | AddExporter(HtmlExporter.Default); 20 | 21 | AddDiagnoser(MemoryDiagnoser.Default); 22 | AddColumn(TargetMethodColumn.Method); 23 | 24 | AddColumn(StatisticColumn.Mean); 25 | AddColumn(StatisticColumn.StdDev); 26 | AddColumn(StatisticColumn.Error); 27 | 28 | AddColumn(BaselineRatioColumn.RatioMean); 29 | AddColumnProvider(DefaultColumnProviders.Metrics); 30 | 31 | AddJob(Job.ShortRun 32 | .WithLaunchCount(1) 33 | .WithWarmupCount(2) 34 | .WithIterationCount(10) 35 | ); 36 | 37 | Options |= ConfigOptions.JoinSummary; 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/Benchmark/Classes/Customer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Benchmark.Classes 4 | { 5 | public class Address 6 | { 7 | public int Id { get; set; } 8 | public string Street { get; set; } 9 | public string City { get; set; } 10 | public string Country { get; set; } 11 | } 12 | 13 | public class AddressDTO 14 | { 15 | public int Id { get; set; } 16 | public string City { get; set; } 17 | public string Country { get; set; } 18 | } 19 | 20 | public class Customer 21 | { 22 | public int Id { get; set; } 23 | public string Name { get; set; } 24 | public decimal? Credit { get; set; } 25 | public Address Address { get; set; } 26 | public Address HomeAddress { get; set; } 27 | public Address[] Addresses { get; set; } 28 | public ICollection
WorkAddresses { get; set; } 29 | } 30 | 31 | public class CustomerDTO 32 | { 33 | public int Id { get; set; } 34 | public string Name { get; set; } 35 | public Address Address { get; set; } 36 | public AddressDTO HomeAddress { get; set; } 37 | public AddressDTO[] Addresses { get; set; } 38 | public List WorkAddresses { get; set; } 39 | public string AddressCity { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Benchmark/Classes/Foo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Benchmark.Classes 5 | { 6 | public class Foo 7 | { 8 | public string Name { get; set; } 9 | 10 | public int Int32 { get; set; } 11 | 12 | public long Int64 { set; get; } 13 | 14 | public int? NullInt { get; set; } 15 | 16 | public float Floatn { get; set; } 17 | 18 | public double Doublen { get; set; } 19 | 20 | public DateTime DateTime { get; set; } 21 | 22 | public Foo Foo1 { get; set; } 23 | 24 | public IEnumerable Foos { get; set; } 25 | 26 | public Foo[] FooArr { get; set; } 27 | 28 | public int[] IntArr { get; set; } 29 | 30 | public IEnumerable Ints { get; set; } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Benchmark/CustomerMapper.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="true" language="C#" #> 2 | <#@ output extension=".g.cs" #> 3 | <# /*@ Assembly Name="/usr/local/share/dotnet/sdk/2.2.103/Microsoft/Microsoft.NET.Build.Extensions/net461/lib/netstandard.dll" */ #> 4 | <#@ Assembly Name="netstandard" #> 5 | <#@ Assembly Name="System.Core" #> 6 | <#@ Assembly Name="System.Runtime" #> 7 | <#@ Assembly Name="System.Linq.Expressions" #> 8 | <#@ Assembly Name="$(TargetDir)/$(ProjectName).dll" #> 9 | <#@ Assembly Name="$(TargetDir)/Mapster.dll" #> 10 | <#@ Assembly Name="$(TargetDir)/ExpressionTranslator.dll" #> 11 | <#@ import namespace="Benchmark.Classes" #> 12 | <#@ import namespace="ExpressionDebugger" #> 13 | <#@ import namespace="Mapster" #> 14 | <# 15 | TypeAdapterConfig.GlobalSettings.SelfContainedCodeGeneration = true; 16 | var foo = default(Customer); 17 | var def = new ExpressionDefinitions 18 | { 19 | IsStatic = true, 20 | MethodName = "Map", 21 | Namespace = "Benchmark", 22 | TypeName = "CustomerMapper" 23 | }; 24 | var code = foo.BuildAdapter() 25 | .CreateMapExpression() 26 | .ToScript(def); 27 | WriteLine(code); 28 | #> -------------------------------------------------------------------------------- /src/Benchmark/FooMapper.g.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | using System.Linq; 4 | using Benchmark.Classes; 5 | using Mapster; 6 | using Mapster.Utils; 7 | 8 | 9 | namespace Benchmark 10 | { 11 | public static partial class FooMapper 12 | { 13 | public static Foo Map(Foo p1) 14 | { 15 | return p1 == null ? null : new Foo() 16 | { 17 | Name = p1.Name, 18 | Int32 = p1.Int32, 19 | Int64 = p1.Int64, 20 | NullInt = p1.NullInt, 21 | Floatn = p1.Floatn, 22 | Doublen = p1.Doublen, 23 | DateTime = p1.DateTime, 24 | Foo1 = Map(p1.Foo1), 25 | Foos = p1.Foos == null ? null : p1.Foos.Select(func1), 26 | FooArr = func2(p1.FooArr), 27 | IntArr = func3(p1.IntArr), 28 | Ints = p1.Ints == null ? null : MapsterHelper.ToEnumerable(p1.Ints) 29 | }; 30 | } 31 | 32 | private static Foo func1(Foo p2) 33 | { 34 | return Map(p2); 35 | } 36 | 37 | private static Foo[] func2(Foo[] p3) 38 | { 39 | if (p3 == null) 40 | { 41 | return null; 42 | } 43 | Foo[] result = new Foo[p3.Length]; 44 | 45 | int v = 0; 46 | 47 | int i = 0; 48 | int len = p3.Length; 49 | 50 | while (i < len) 51 | { 52 | Foo item = p3[i]; 53 | result[v++] = Map(item); 54 | i++; 55 | } 56 | return result; 57 | 58 | } 59 | 60 | private static int[] func3(int[] p4) 61 | { 62 | if (p4 == null) 63 | { 64 | return null; 65 | } 66 | int[] result = new int[p4.Length]; 67 | Array.Copy(p4, 0, result, 0, p4.Length); 68 | return result; 69 | 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Benchmark/FooMapper.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="true" language="C#" #> 2 | <#@ output extension=".g.cs" #> 3 | <# /*@ Assembly Name="/usr/local/share/dotnet/sdk/2.2.103/Microsoft/Microsoft.NET.Build.Extensions/net461/lib/netstandard.dll" */ #> 4 | <#@ Assembly Name="netstandard" #> 5 | <#@ Assembly Name="System.Core" #> 6 | <#@ Assembly Name="System.Runtime" #> 7 | <#@ Assembly Name="System.Linq.Expressions" #> 8 | <#@ Assembly Name="$(TargetDir)/Benchmark.dll" #> 9 | <#@ Assembly Name="$(TargetDir)/Mapster.dll" #> 10 | <#@ Assembly Name="$(TargetDir)/ExpressionTranslator.dll" #> 11 | <#@ import namespace="Benchmark.Classes" #> 12 | <#@ import namespace="ExpressionDebugger" #> 13 | <#@ import namespace="Mapster" #> 14 | <# 15 | TypeAdapterConfig.GlobalSettings.SelfContainedCodeGeneration = true; 16 | var foo = default(Foo); 17 | var def = new ExpressionDefinitions 18 | { 19 | IsStatic = true, 20 | MethodName = "Map", 21 | Namespace = "Benchmark", 22 | TypeName = "FooMapper" 23 | }; 24 | var code = foo.BuildAdapter() 25 | .CreateMapExpression() 26 | .ToScript(def); 27 | code = code.Replace("TypeAdapter.Map.Invoke", "Map"); 28 | WriteLine(code); 29 | #> -------------------------------------------------------------------------------- /src/Benchmark/Program.cs: -------------------------------------------------------------------------------- 1 | using Benchmark.Benchmarks; 2 | using BenchmarkDotNet.Running; 3 | 4 | namespace Benchmark 5 | { 6 | class Program 7 | { 8 | static void Main(string[] args) 9 | { 10 | var switcher = new BenchmarkSwitcher(new[] 11 | { 12 | typeof(TestSimpleTypes), 13 | typeof(TestComplexTypes), 14 | typeof(TestAll), 15 | }); 16 | 17 | switcher.Run(args, new Config()); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 8 | chaowlert;eric_swann;andrerav 9 | Copyright (c) $([System.DateTime]::Now.ToString(`yyyy`)) Chaowlert Chaisrichalermpol, Eric Swann, Andreas Ravnestad 10 | false 11 | https://github.com/MapsterMapper/Mapster 12 | https://github.com/MapsterMapper/Mapster 13 | 14 | logo.png 15 | https://cloud.githubusercontent.com/assets/5763993/26522718/d16f3e42-4330-11e7-9b78-f8c7402624e7.png 16 | MIT 17 | true 18 | $(SolutionDir)/Mapster/Mapster.snk 19 | true 20 | Mapper;AutoMapper;Fast;Mapping 21 | icon.png 22 | false 23 | 10 24 | 25 | -------------------------------------------------------------------------------- /src/ExpressionDebugger.Console/ExpressionDebugger.Console.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net6.0;net7.0 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/ExpressionDebugger.Console/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace ExpressionDebugger.Console 5 | { 6 | class Program 7 | { 8 | static void Main(string[] args) 9 | { 10 | var p1 = Expression.Parameter(typeof(int)); 11 | var p2 = Expression.Parameter(typeof(int)); 12 | var body = Expression.Add(p1, Expression.Block( 13 | new Expression[] { 14 | Expression.Call(typeof(System.Console).GetMethod("WriteLine", new [] { typeof(int) }), p2), 15 | p2, 16 | })); 17 | var lambda = Expression.Lambda>(body, p1, p2); 18 | 19 | var script = lambda.ToScript(); 20 | 21 | var fun = lambda.CompileWithDebugInfo(); 22 | var result = fun(1, 2); 23 | System.Console.WriteLine(result); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ExpressionDebugger.Tests/ExpressionDebugger.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0;net7.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/ExpressionDebugger/ExpressionCompilationOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Reflection; 3 | 4 | namespace ExpressionDebugger 5 | { 6 | public class ExpressionCompilationOptions 7 | { 8 | public ExpressionDefinitions? DefaultDefinitions { get; set; } 9 | public IEnumerable? References { get; set; } 10 | public bool EmitFile { get; set; } 11 | public string? RootPath { get; set; } 12 | public bool? IsRelease { get; set; } 13 | public bool ThrowOnFailedCompilation { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ExpressionDebugger/ExpressionDebugger.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0;net7.0 5 | True 6 | Chaowlert Chaisrichalermpol 7 | Step into debugging from linq expressions 8 | https://github.com/chaowlert/ExpressionDebugger 9 | https://github.com/chaowlert/ExpressionDebugger 10 | expression;linq;debug 11 | https://cloud.githubusercontent.com/assets/5763993/26522656/41e28a6e-432f-11e7-9cae-7856f927d1a1.png 12 | True 13 | true 14 | ExpressionDebugger.snk 15 | 2.2.0 16 | https://github.com/chaowlert/ExpressionDebugger/blob/master/LICENSE 17 | 8.0 18 | enable 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/ExpressionDebugger/ExpressionDebugger.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/ExpressionDebugger/ExpressionDebugger.snk -------------------------------------------------------------------------------- /src/ExpressionTranslator/ExpressionDefinitions.cs: -------------------------------------------------------------------------------- 1 | namespace ExpressionDebugger 2 | { 3 | public class ExpressionDefinitions : TypeDefinitions 4 | { 5 | public string? MethodName { get; set; } 6 | public bool IsExpression { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/ExpressionTranslator/ExpressionTranslator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0;net7.0 5 | True 6 | Chaowlert Chaisrichalermpol 7 | Translate from linq expressions to C# code 8 | https://github.com/chaowlert/ExpressionDebugger 9 | https://github.com/chaowlert/ExpressionDebugger 10 | expression;linq;debug 11 | https://cloud.githubusercontent.com/assets/5763993/26522656/41e28a6e-432f-11e7-9cae-7856f927d1a1.png 12 | True 13 | true 14 | ExpressionTranslator.snk 15 | 2.4.3 16 | ExpressionDebugger 17 | MIT 18 | icon.png 19 | 20 | 8.0 21 | enable 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/ExpressionTranslator/ExpressionTranslator.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/ExpressionTranslator/ExpressionTranslator.snk -------------------------------------------------------------------------------- /src/ExpressionTranslator/ExpressionTranslatorExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace ExpressionDebugger 5 | { 6 | public static class ExpressionTranslatorExtensions 7 | { 8 | /// 9 | /// Generate script text 10 | /// 11 | public static string ToScript(this Expression node, ExpressionDefinitions? definitions = null) 12 | { 13 | var translator = ExpressionTranslator.Create(node, definitions); 14 | return translator.ToString(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ExpressionTranslator/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | 7 | namespace ExpressionDebugger 8 | { 9 | internal static class Extensions 10 | { 11 | public static HashSet ToHashSet(this IEnumerable source) 12 | { 13 | return new HashSet(source); 14 | } 15 | 16 | #if NET40 17 | public static Type GetTypeInfo(this Type type) { 18 | return type; 19 | } 20 | #endif 21 | 22 | #if NET40 || NETSTANDARD1_3 || NET6_0_OR_GREATER 23 | public static T GetCustomAttribute(this MemberInfo memberInfo) where T : Attribute 24 | { 25 | return (T)memberInfo.GetCustomAttributes(typeof(T), true).SingleOrDefault(); 26 | } 27 | 28 | public static T GetCustomAttribute(this Type type) where T : Attribute 29 | { 30 | return (T)type.GetTypeInfo().GetCustomAttributes(typeof(T), true).SingleOrDefault(); 31 | } 32 | #endif 33 | 34 | public static int FindStartIndex(this StringBuilder sb) 35 | { 36 | int wsCount = 0; 37 | for (int i = 0; i < sb.Length; i++) 38 | { 39 | if (char.IsWhiteSpace(sb[i])) 40 | wsCount++; 41 | else 42 | break; 43 | } 44 | return wsCount; 45 | } 46 | 47 | public static int FindEndIndex(this StringBuilder sb) 48 | { 49 | int wsCount = 0; 50 | for (int i = sb.Length - 1; i >= 0; i--) 51 | { 52 | if (char.IsWhiteSpace(sb[i])) 53 | wsCount++; 54 | else 55 | break; 56 | } 57 | return sb.Length - wsCount; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/ExpressionTranslator/PropertyDefinitions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | 5 | namespace ExpressionDebugger 6 | { 7 | public class PropertyDefinitions 8 | { 9 | public Type Type { get; set; } 10 | public string Name { get; set; } 11 | public bool IsReadOnly { get; set; } 12 | public bool IsInitOnly { get; set; } 13 | 14 | /// 15 | /// Set to 2 to mark type as nullable 16 | /// 17 | public byte? NullableContext { get; set; } 18 | 19 | /// 20 | /// If type is generic, array or tuple, you can mark nullable for each type 21 | /// Set to 2 for nullable 22 | /// 23 | public byte[]? Nullable { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ExpressionTranslator/TypeDefinitions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace ExpressionDebugger 5 | { 6 | public class TypeDefinitions 7 | { 8 | public string? Namespace { get; set; } 9 | public string? TypeName { get; set; } 10 | public bool IsStatic { get; set; } 11 | public bool IsInternal { get; set; } 12 | public IEnumerable? Implements { get; set; } 13 | public bool PrintFullTypeName { get; set; } 14 | public bool IsRecordType { get; set; } 15 | 16 | /// 17 | /// Set to 2 to mark all properties as nullable 18 | /// 19 | public byte? NullableContext { get; set; } 20 | } 21 | } -------------------------------------------------------------------------------- /src/ExpressionTranslator/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/ExpressionTranslator/icon.png -------------------------------------------------------------------------------- /src/Mapster.Async.Tests/Mapster.Async.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0;net6.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Mapster.Async/Mapster.Async.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0;net6.0 5 | Async supports for Mapster 6 | true 7 | Mapster;Async 8 | true 9 | Mapster.Async.snk 10 | 2.0.1-pre02 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Mapster.Async/Mapster.Async.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.Async/Mapster.Async.snk -------------------------------------------------------------------------------- /src/Mapster.Async/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.Async/icon.png -------------------------------------------------------------------------------- /src/Mapster.Core/Attributes/AdaptIgnoreAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mapster 4 | { 5 | [AttributeUsage(AttributeTargets.Field 6 | | AttributeTargets.Property)] 7 | public class AdaptIgnoreAttribute : Attribute 8 | { 9 | public MemberSide? Side { get; set; } 10 | 11 | public AdaptIgnoreAttribute() { } 12 | 13 | public AdaptIgnoreAttribute(MemberSide side) 14 | { 15 | this.Side = side; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Mapster.Core/Attributes/AdaptMemberAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mapster 4 | { 5 | [AttributeUsage(AttributeTargets.Field 6 | | AttributeTargets.Parameter 7 | | AttributeTargets.Property)] 8 | public class AdaptMemberAttribute : Attribute 9 | { 10 | public string? Name { get; set; } 11 | public MemberSide? Side { get; set; } 12 | 13 | public AdaptMemberAttribute() { } 14 | public AdaptMemberAttribute(string name) 15 | { 16 | this.Name = name; 17 | } 18 | public AdaptMemberAttribute(string name, MemberSide side) 19 | { 20 | this.Name = name; 21 | this.Side = side; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Mapster.Core/Attributes/GenerateMapperAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mapster 4 | { 5 | [AttributeUsage(AttributeTargets.Class 6 | | AttributeTargets.Struct 7 | | AttributeTargets.Interface)] 8 | public class GenerateMapperAttribute : Attribute 9 | { 10 | public string Name { get; set; } = "[name]Mapper"; 11 | public Type[]? ForAttributes { get; set; } 12 | public bool IsHelperClass { get; set; } 13 | public bool IsInternal { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Mapster.Core/Attributes/MapperAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mapster 4 | { 5 | [AttributeUsage(AttributeTargets.Interface)] 6 | public class MapperAttribute : Attribute 7 | { 8 | public string? Name { get; set; } 9 | public bool IsInternal { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/Mapster.Core/Attributes/PropertyTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mapster 4 | { 5 | [AttributeUsage(AttributeTargets.Class 6 | | AttributeTargets.Struct 7 | | AttributeTargets.Interface 8 | | AttributeTargets.Property 9 | | AttributeTargets.Field, AllowMultiple = true)] 10 | public class PropertyTypeAttribute : Attribute 11 | { 12 | public Type Type { get; } 13 | public Type[]? ForAttributes { get; set; } 14 | 15 | public PropertyTypeAttribute(Type type) 16 | { 17 | this.Type = type; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Mapster.Core/Attributes/UseDestinationValueAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mapster 4 | { 5 | [AttributeUsage(AttributeTargets.Field 6 | | AttributeTargets.Property)] 7 | public class UseDestinationValueAttribute : Attribute 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Mapster.Core/Enums/MapType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mapster 4 | { 5 | [Flags] 6 | public enum MapType 7 | { 8 | Map = 1, 9 | MapToTarget = 2, 10 | Projection = 4, 11 | } 12 | } -------------------------------------------------------------------------------- /src/Mapster.Core/Enums/MemberSide.cs: -------------------------------------------------------------------------------- 1 | namespace Mapster 2 | { 3 | public enum MemberSide 4 | { 5 | Source, 6 | Destination, 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Mapster.Core/MapContext/MapContext.cs: -------------------------------------------------------------------------------- 1 | using Mapster.Utils; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Threading; 5 | namespace Mapster 6 | { 7 | /// 8 | /// This class is to send data between mapping process 9 | /// 10 | /// 11 | /// The idea of this class is similar to Transaction & TransactionScope 12 | /// You can get context by MapContext.Current 13 | /// And all mapping processes will having only one context 14 | /// 15 | public class MapContext 16 | { 17 | #if (NETSTANDARD || NET6_0_OR_GREATER) && !MAPSTER_FORCE_LEGACY_MAPCONTEXT 18 | private static readonly AsyncLocal _localContext = new AsyncLocal(); 19 | public static MapContext? Current 20 | { 21 | get => _localContext.Value; 22 | set => _localContext.Value = value; 23 | } 24 | #else 25 | [field: ThreadStatic] 26 | public static MapContext? Current { get; set; } 27 | #endif 28 | 29 | private Dictionary? _references; 30 | public Dictionary References => _references ??= new Dictionary(); 31 | 32 | private Dictionary? _parameters; 33 | public Dictionary Parameters => _parameters ??= new Dictionary(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Mapster.Core/MapContext/MapContextScope.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Mapster.Utils; 3 | 4 | namespace Mapster 5 | { 6 | public class MapContextScope : IDisposable 7 | { 8 | public static MapContextScope Required() 9 | { 10 | return new MapContextScope(); 11 | } 12 | 13 | public static MapContextScope RequiresNew() 14 | { 15 | return new MapContextScope(true); 16 | } 17 | 18 | public MapContext Context { get; } 19 | 20 | private readonly MapContext? _previousContext; 21 | 22 | public MapContextScope() : this(false) { } 23 | public MapContextScope(bool ignorePreviousContext) 24 | { 25 | _previousContext = MapContext.Current; 26 | 27 | this.Context = ignorePreviousContext 28 | ? new MapContext() 29 | : _previousContext ?? new MapContext(); 30 | 31 | MapContext.Current = this.Context; 32 | } 33 | 34 | public void Dispose() 35 | { 36 | MapContext.Current = _previousContext; 37 | } 38 | 39 | public static TResult GetOrAddMapReference(ReferenceTuple key, Func mapFn) where TResult : notnull 40 | { 41 | using var context = new MapContextScope(); 42 | var dict = context.Context.References; 43 | if (!dict.TryGetValue(key, out var reference)) 44 | dict[key] = reference = mapFn(key); 45 | return (TResult)reference; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Mapster.Core/Mapster.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Lightweight library for Mapster and Mapster CodeGen 4 | net7.0;net6.0 5 | Mapster.Core 6 | mapster 7 | 1.2.1-pre04 8 | enable 9 | true 10 | true 11 | Mapster.Core.snk 12 | Mapster 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Mapster.Core/Mapster.Core.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | True 5 | True -------------------------------------------------------------------------------- /src/Mapster.Core/Mapster.Core.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.Core/Mapster.Core.snk -------------------------------------------------------------------------------- /src/Mapster.Core/Models/Never.cs: -------------------------------------------------------------------------------- 1 | namespace Mapster.Models 2 | { 3 | public struct Never { } 4 | } 5 | -------------------------------------------------------------------------------- /src/Mapster.Core/Register/CodeGenerationConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Mapster 4 | { 5 | public class CodeGenerationConfig 6 | { 7 | public List AdaptAttributeBuilders { get; } = new List(); 8 | public List GenerateMapperAttributeBuilders { get; } = new List(); 9 | public AdaptAttributeBuilder Default { get; } = new AdaptAttributeBuilder(new AdaptFromAttribute("void")); 10 | 11 | public AdaptAttributeBuilder AdaptTo(string name, MapType? mapType = null) 12 | { 13 | var builder = new AdaptAttributeBuilder(new AdaptToAttribute(name) {MapType = mapType ?? 0}); 14 | AdaptAttributeBuilders.Add(builder); 15 | return builder; 16 | } 17 | 18 | public AdaptAttributeBuilder AdaptFrom(string name, MapType? mapType = null) 19 | { 20 | var builder = new AdaptAttributeBuilder(new AdaptFromAttribute(name) {MapType = mapType ?? 0}); 21 | AdaptAttributeBuilders.Add(builder); 22 | return builder; 23 | } 24 | 25 | public AdaptAttributeBuilder AdaptTwoWays(string name, MapType? mapType = null) 26 | { 27 | var builder = new AdaptAttributeBuilder(new AdaptTwoWaysAttribute(name) {MapType = mapType ?? 0}); 28 | AdaptAttributeBuilders.Add(builder); 29 | return builder; 30 | } 31 | 32 | public GenerateMapperAttributeBuilder GenerateMapper(string name) 33 | { 34 | var builder = new GenerateMapperAttributeBuilder(new GenerateMapperAttribute()); 35 | GenerateMapperAttributeBuilders.Add(builder); 36 | return builder; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/Mapster.Core/Register/GenerateMapperAttributeBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace Mapster 7 | { 8 | public class GenerateMapperAttributeBuilder 9 | { 10 | public GenerateMapperAttribute Attribute { get; } 11 | public HashSet Types { get; } = new HashSet(); 12 | 13 | public GenerateMapperAttributeBuilder(GenerateMapperAttribute attribute) 14 | { 15 | this.Attribute = attribute; 16 | } 17 | 18 | public GenerateMapperAttributeBuilder ForTypes(params Type[] types) 19 | { 20 | this.Types.UnionWith(types); 21 | return this; 22 | } 23 | 24 | public GenerateMapperAttributeBuilder ForAllTypesInNamespace(Assembly assembly, string @namespace) 25 | { 26 | this.Types.UnionWith( 27 | assembly.GetTypes() 28 | .Where(it => (it.Namespace == @namespace || it.Namespace?.StartsWith(@namespace + '.') == true) && 29 | !it.Name.Contains('<'))); 30 | return this; 31 | } 32 | 33 | public GenerateMapperAttributeBuilder ForType() 34 | { 35 | this.Types.Add(typeof(T)); 36 | return this; 37 | } 38 | 39 | public GenerateMapperAttributeBuilder ExcludeTypes(params Type[] types) 40 | { 41 | this.Types.ExceptWith(types); 42 | return this; 43 | } 44 | 45 | public GenerateMapperAttributeBuilder ExcludeTypes(Predicate predicate) 46 | { 47 | this.Types.RemoveWhere(predicate); 48 | return this; 49 | } 50 | 51 | } 52 | } -------------------------------------------------------------------------------- /src/Mapster.Core/Register/ICodeGenerationRegister.cs: -------------------------------------------------------------------------------- 1 | namespace Mapster 2 | { 3 | public interface ICodeGenerationRegister 4 | { 5 | void Register(CodeGenerationConfig config); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/Mapster.Core/Register/PropertySetting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace Mapster 5 | { 6 | public class PropertySetting 7 | { 8 | public bool Ignore { get; set; } 9 | public string? TargetPropertyName { get; set; } 10 | public Type? TargetPropertyType { get; set; } 11 | public LambdaExpression? MapFunc { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Mapster.Core/Utils/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | 7 | namespace Mapster.Utils 8 | { 9 | public static class Extensions 10 | { 11 | #if NET40 12 | public static Type GetTypeInfo(this Type type) 13 | { 14 | return type; 15 | } 16 | #endif 17 | 18 | public static string GetMemberName(this LambdaExpression lambda) 19 | { 20 | string? prop = null; 21 | var expr = lambda.Body; 22 | if (expr.NodeType == ExpressionType.MemberAccess) 23 | { 24 | var memEx = (MemberExpression)expr; 25 | prop = memEx.Member.Name; 26 | expr = (Expression?)memEx.Expression; 27 | } 28 | if (prop == null || expr?.NodeType != ExpressionType.Parameter) 29 | throw new ArgumentException("Allow only first level member access (eg. obj => obj.Name)", nameof(lambda)); 30 | return prop; 31 | } 32 | 33 | public static IEnumerable GetLoadableTypes(this Assembly assembly) 34 | { 35 | try 36 | { 37 | return assembly.GetTypes(); 38 | } 39 | catch (ReflectionTypeLoadException e) 40 | { 41 | return e.Types.Where(t => t != null).Cast(); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Mapster.Core/Utils/ReferenceTuple.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace Mapster.Utils 5 | { 6 | public readonly struct ReferenceTuple : IEquatable 7 | { 8 | public object Reference { get; } 9 | public Type DestinationType { get; } 10 | public ReferenceTuple(object reference, Type destinationType) 11 | { 12 | this.Reference = reference; 13 | this.DestinationType = destinationType; 14 | } 15 | 16 | public override bool Equals(object obj) 17 | { 18 | return obj is ReferenceTuple other && Equals(other); 19 | } 20 | 21 | public bool Equals(ReferenceTuple other) 22 | { 23 | return ReferenceEquals(this.Reference, other.Reference) 24 | && this.DestinationType == other.DestinationType; 25 | } 26 | 27 | public override int GetHashCode() 28 | { 29 | unchecked 30 | { 31 | return (RuntimeHelpers.GetHashCode(this.Reference) * 397) ^ DestinationType.GetHashCode(); 32 | } 33 | } 34 | 35 | public static bool operator ==(ReferenceTuple left, ReferenceTuple right) 36 | { 37 | return left.Equals(right); 38 | } 39 | 40 | public static bool operator !=(ReferenceTuple left, ReferenceTuple right) 41 | { 42 | return !(left == right); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Mapster.Core/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.Core/icon.png -------------------------------------------------------------------------------- /src/Mapster.DependencyInjection.Tests/Mapster.DependencyInjection.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0;net6.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Mapster.DependencyInjection/Mapster.DependencyInjection.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0;net6.0 5 | Dependency Injection supports for Mapster 6 | true 7 | Mapster;DependencyInjection 8 | true 9 | Mapster.DependencyInjection.snk 10 | 1.0.1-pre02 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Mapster.DependencyInjection/Mapster.DependencyInjection.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.DependencyInjection/Mapster.DependencyInjection.snk -------------------------------------------------------------------------------- /src/Mapster.DependencyInjection/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using MapsterMapper; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace Mapster 5 | { 6 | public static class ServiceCollectionExtensions 7 | { 8 | public static void AddMapster(this IServiceCollection serviceCollection) 9 | { 10 | serviceCollection.AddTransient(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Mapster.DependencyInjection/TypeAdapterExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MapsterMapper; 4 | 5 | namespace Mapster 6 | { 7 | public static class TypeAdapterExtensions 8 | { 9 | internal static U GetValueOrDefault(this IDictionary dict, T key) 10 | { 11 | return dict.TryGetValue(key, out var value) ? value : default; 12 | } 13 | 14 | public static TService GetService(this MapContext context) 15 | { 16 | var sp = (IServiceProvider) context?.Parameters.GetValueOrDefault(ServiceMapper.DI_KEY); 17 | if (sp == null) 18 | throw new InvalidOperationException("Mapping must be called using ServiceAdapter"); 19 | return (TService)sp.GetService(typeof(TService)); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Mapster.DependencyInjection/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.DependencyInjection/icon.png -------------------------------------------------------------------------------- /src/Mapster.EF6/Mapster.EF6.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0;net6.0 5 | EF6 plugin for Mapster 6 | true 7 | Mapster;EF6 8 | True 9 | true 10 | Mapster.EF6.snk 11 | 2.0.1-pre02 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Mapster.EF6/Mapster.EF6.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.EF6/Mapster.EF6.snk -------------------------------------------------------------------------------- /src/Mapster.EF6/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.EF6/icon.png -------------------------------------------------------------------------------- /src/Mapster.EF6/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Mapster.EFCore.Tests/Mapster.EFCore.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0;net6.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Mapster.EFCore.Tests/Models/Course.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace Mapster.EFCore.Tests.Models 5 | { 6 | public class Course 7 | { 8 | [DatabaseGenerated(DatabaseGeneratedOption.None)] 9 | public int CourseID { get; set; } 10 | public string Title { get; set; } 11 | public int Credits { get; set; } 12 | 13 | public ICollection Enrollments { get; set; } 14 | }} 15 | -------------------------------------------------------------------------------- /src/Mapster.EFCore.Tests/Models/Enrollment.cs: -------------------------------------------------------------------------------- 1 | namespace Mapster.EFCore.Tests.Models 2 | { 3 | public enum Grade 4 | { 5 | A, B, C, D, F 6 | } 7 | 8 | public class Enrollment 9 | { 10 | public int EnrollmentID { get; set; } 11 | public int CourseID { get; set; } 12 | public int StudentID { get; set; } 13 | public Grade? Grade { get; set; } 14 | 15 | public Course Course { get; set; } 16 | public Student Student { get; set; } 17 | }} 18 | -------------------------------------------------------------------------------- /src/Mapster.EFCore.Tests/Models/SchoolContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace Mapster.EFCore.Tests.Models 4 | { 5 | public class SchoolContext : DbContext 6 | { 7 | public SchoolContext(DbContextOptions options) : base(options) 8 | { 9 | } 10 | 11 | public DbSet Courses { get; set; } 12 | public DbSet Enrollments { get; set; } 13 | public DbSet Students { get; set; } 14 | }} 15 | -------------------------------------------------------------------------------- /src/Mapster.EFCore.Tests/Models/Student.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Mapster.EFCore.Tests.Models 5 | { 6 | public class Student 7 | { 8 | public int ID { get; set; } 9 | public string LastName { get; set; } 10 | public string FirstMidName { get; set; } 11 | public DateTime EnrollmentDate { get; set; } 12 | 13 | public ICollection Enrollments { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Mapster.EFCore/Mapster.EFCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0;net6.0 5 | EFCore plugin for Mapster 6 | true 7 | Mapster;EFCore 8 | True 9 | true 10 | Mapster.EFCore.snk 11 | 5.1.1-pre02 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Mapster.EFCore/Mapster.EFCore.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.EFCore/Mapster.EFCore.snk -------------------------------------------------------------------------------- /src/Mapster.EFCore/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.EFCore/icon.png -------------------------------------------------------------------------------- /src/Mapster.EFCore/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Mapster.Immutable.Tests/ImmutableTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.Immutable; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using Shouldly; 5 | 6 | namespace Mapster.Immutable.Tests 7 | { 8 | [TestClass] 9 | public class TestImmutable 10 | { 11 | [TestMethod] 12 | public void TestImmutableArray() 13 | { 14 | var config = new TypeAdapterConfig(); 15 | config.EnableImmutableMapping(); 16 | 17 | var list = new[] {1, 2, 3, 4}; 18 | var array = list.Adapt>(config); 19 | array.ShouldBe(list); 20 | } 21 | 22 | [TestMethod] 23 | public void TestImmutableDictionary() 24 | { 25 | var config = new TypeAdapterConfig(); 26 | config.EnableImmutableMapping(); 27 | 28 | var poco = new {Name = "Foo", Id = "Bar"}; 29 | var dict = poco.Adapt>(config); 30 | dict["Name"].ShouldBe(poco.Name); 31 | dict["Id"].ShouldBe(poco.Id); 32 | } 33 | 34 | [TestMethod] 35 | public void TestImmutableDictionary2() 36 | { 37 | var config = new TypeAdapterConfig(); 38 | config.EnableImmutableMapping(); 39 | 40 | var list = new Dictionary 41 | { 42 | [1] = 2, 43 | [3] = 4, 44 | }; 45 | var dict = list.Adapt>(config); 46 | dict.ShouldBe(list); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Mapster.Immutable.Tests/Mapster.Immutable.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0;net6.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Mapster.Immutable/Mapster.Immutable.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0;net6.0 5 | Immutable collection supports for Mapster 6 | true 7 | Mapster;Immutable 8 | true 9 | Mapster.Immutable.snk 10 | 1.0.1-pre02 11 | enable 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Mapster.Immutable/Mapster.Immutable.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.Immutable/Mapster.Immutable.snk -------------------------------------------------------------------------------- /src/Mapster.Immutable/TypeAdapterConfigExtensions.cs: -------------------------------------------------------------------------------- 1 | using Mapster.Immutable; 2 | 3 | namespace Mapster 4 | { 5 | public static class TypeAdapterConfigExtensions 6 | { 7 | public static void EnableImmutableMapping(this TypeAdapterConfig config) 8 | { 9 | config.Rules.Add(new ImmutableAdapter().CreateRule()); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Mapster.Immutable/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.Immutable/icon.png -------------------------------------------------------------------------------- /src/Mapster.JsonNet.Tests/JsonMappingTest.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Newtonsoft.Json.Linq; 3 | using Shouldly; 4 | 5 | namespace Mapster.JsonNet.Tests 6 | { 7 | [TestClass] 8 | public class JsonMappingTest 9 | { 10 | private static TypeAdapterConfig _config; 11 | 12 | [ClassInitialize] 13 | public static void Setup(TestContext context) 14 | { 15 | _config = new TypeAdapterConfig(); 16 | _config.EnableJsonMapping(); 17 | } 18 | 19 | [TestMethod] 20 | public void JsonToJson() 21 | { 22 | var json = new JObject(); 23 | var result = json.Adapt(_config); 24 | result.ShouldBe(json); 25 | } 26 | 27 | [TestMethod] 28 | public void FromString() 29 | { 30 | var str = @"{ ""foo"": ""bar"" }"; 31 | var result = str.Adapt(_config); 32 | result["foo"].ShouldBe("bar"); 33 | } 34 | 35 | [TestMethod] 36 | public void ToStringTest() 37 | { 38 | var json = new JObject {["foo"] = "bar"}; 39 | var result = json.Adapt(_config); 40 | result.ShouldContainWithoutWhitespace(@"{""foo"":""bar""}"); 41 | } 42 | 43 | [TestMethod] 44 | public void FromObject() 45 | { 46 | var obj = new Mock {foo = "bar"}; 47 | var result = obj.Adapt(_config); 48 | result["foo"].ShouldBe("bar"); 49 | } 50 | 51 | [TestMethod] 52 | public void ToObject() 53 | { 54 | var json = new JObject { ["foo"] = "bar" }; 55 | var result = json.Adapt(_config); 56 | result.foo.ShouldBe("bar"); 57 | } 58 | } 59 | 60 | public class Mock 61 | { 62 | public string foo { get; set; } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Mapster.JsonNet.Tests/Mapster.JsonNet.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0;net6.0 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Mapster.JsonNet/Mapster.JsonNet.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0;net6.0 5 | Json.net conversion supports for Mapster 6 | true 7 | Mapster;Json.net 8 | true 9 | Mapster.JsonNet.snk 10 | 1.1.1-pre03 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Mapster.JsonNet/Mapster.JsonNet.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.JsonNet/Mapster.JsonNet.snk -------------------------------------------------------------------------------- /src/Mapster.JsonNet/TypeAdapterConfigExtensions.cs: -------------------------------------------------------------------------------- 1 | using Mapster.JsonNet; 2 | 3 | namespace Mapster 4 | { 5 | public static class TypeAdapterConfigExtensions 6 | { 7 | public static void EnableJsonMapping(this TypeAdapterConfig config) 8 | { 9 | config.Rules.Add(new JsonAdapter().CreateRule()); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Mapster.JsonNet/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.JsonNet/icon.png -------------------------------------------------------------------------------- /src/Mapster.SourceGenerator/Mapster.SourceGenerator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0;net6.0 5 | Source generator to generate mapping using Mapster 6 | source-generator;mapster 7 | true 8 | Mapster.SourceGenerator.snk 9 | https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json ;$(RestoreAdditionalProjectSources) 10 | 6.5.1 11 | enable 12 | false 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Mapster.SourceGenerator/Mapster.SourceGenerator.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.SourceGenerator/Mapster.SourceGenerator.snk -------------------------------------------------------------------------------- /src/Mapster.SourceGenerator/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.SourceGenerator/icon.png -------------------------------------------------------------------------------- /src/Mapster.Tests/Classes/Address.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations.Schema; 2 | 3 | namespace Mapster.Tests.Classes 4 | { 5 | [ComplexType] 6 | public class Address 7 | { 8 | public string Street { get; set; } 9 | public string ZipCode { get; set; } 10 | public string Country { get; set; } 11 | public string City { get; set; } 12 | public AddressType AddressType { get; set; } 13 | } 14 | 15 | public enum AddressType 16 | { 17 | Work = 1, 18 | Home = 2 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Mapster.Tests/Classes/Customer.cs: -------------------------------------------------------------------------------- 1 | namespace Mapster.Tests.Classes 2 | { 3 | public class Customer 4 | { 5 | public int Id { get; set; } 6 | public string Name { get; set; } 7 | public string Surname { get; set; } 8 | public Address Address { get; set; } 9 | } 10 | 11 | public class CustomerDTO 12 | { 13 | public int Id { get; set; } 14 | public string Name { get; set; } 15 | public string Address_Country { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Mapster.Tests/Diagnostics/DebugInfoInjectorEx.cs: -------------------------------------------------------------------------------- 1 | using ExpressionDebugger; 2 | using System; 3 | using System.IO; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | using System.Reflection.Emit; 7 | 8 | namespace Mapster.Diagnostics 9 | { 10 | public class DebugInfoInjectorEx: DebugInfoInjector 11 | { 12 | public DebugInfoInjectorEx(string filename): base (filename) { } 13 | 14 | public DebugInfoInjectorEx(TextWriter writer): base(writer) { } 15 | 16 | protected override Expression VisitConstant(ConstantExpression node) 17 | { 18 | node = (ConstantExpression)base.VisitConstant(node); 19 | 20 | if (CanEmitConstant(node.Value, node.Type)) 21 | return node; 22 | 23 | return GetNonPublicObject(node.Value, node.Type); 24 | } 25 | 26 | private static Expression GetNonPublicObject(object value, Type type) 27 | { 28 | var i = GlobalReference.GetIndex(value); 29 | return Expression.Convert( 30 | Expression.Call( 31 | typeof(GlobalReference).GetMethod(nameof(GlobalReference.GetObject)), 32 | Expression.Constant(i)), 33 | type); 34 | } 35 | 36 | private static bool CanEmitConstant(object value, Type type) 37 | { 38 | if (value == null 39 | || type.IsPrimitive 40 | || type == typeof(string) 41 | || type == typeof(decimal)) 42 | return true; 43 | 44 | if (value is Type t) 45 | return IsVisible(t); 46 | 47 | if (value is MethodBase mb) 48 | return IsVisible(mb); 49 | 50 | return false; 51 | } 52 | 53 | private static bool IsVisible(Type t) 54 | { 55 | return t is TypeBuilder 56 | || t.IsGenericParameter 57 | || t.IsVisible; 58 | } 59 | 60 | private static bool IsVisible(MethodBase mb) 61 | { 62 | if (mb is DynamicMethod || !mb.IsPublic) 63 | return false; 64 | 65 | Type dt = mb.DeclaringType; 66 | return dt == null || IsVisible(dt); 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/Mapster.Tests/Diagnostics/GlobalReference.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace ExpressionDebugger 4 | { 5 | public static class GlobalReference 6 | { 7 | private static readonly List _references = new List(); 8 | private static readonly Dictionary _dict = new Dictionary(); 9 | 10 | public static int GetIndex(object obj) 11 | { 12 | if (_dict.TryGetValue(obj, out var id)) 13 | return id; 14 | lock (_references) 15 | { 16 | if (_dict.TryGetValue(obj, out id)) 17 | return id; 18 | id = _references.Count; 19 | _references.Add(obj); 20 | _dict[obj] = id; 21 | return id; 22 | } 23 | } 24 | 25 | public static object GetObject(int i) 26 | { 27 | return _references[i]; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Mapster.Tests/Mapster.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0;net6.0 5 | false 6 | Mapster.Tests 7 | Mapster.Tests.snk 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/Mapster.Tests/Mapster.Tests.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.Tests/Mapster.Tests.snk -------------------------------------------------------------------------------- /src/Mapster.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTrademark("")] 9 | [assembly: AssemblyCulture("")] 10 | 11 | // Setting ComVisible to false makes the types in this assembly not visible 12 | // to COM components. If you need to access a type in this assembly from 13 | // COM, set the ComVisible attribute to true on that type. 14 | [assembly: ComVisible(false)] 15 | 16 | // The following GUID is for the ID of the typelib if this project is exposed to COM 17 | [assembly: Guid("08321745-c5e2-48a8-bef2-e0b17290d38f")] 18 | 19 | // Version information for an assembly consists of the following four values: 20 | // 21 | // Major Version 22 | // Minor Version 23 | // Build Number 24 | // Revision 25 | // 26 | // You can specify all the values or you can default the Build and Revision Numbers 27 | // by using the '*' as shown below: 28 | // [assembly: AssemblyVersion("1.0.*")] 29 | [assembly: InternalsVisibleTo("Mapster.Dynamic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100ED6C7EE4B2E0AC62548FAA596F267469CD877990306F7C97ACBD889455E5D5846FFC5DCD5D87A72263DC7EB276629261C115DA3456485AE051D0C4EDBED3DD1A0092280F6408407D88FF3A76F2E6EECA4DE369E31A2A631052C99CAC2105B9A273969A66B076D5FC2B9B57F8E45D358906F58A0D959EA9BA2D725131A0E372AB")] 30 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenCompilingConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.VisualStudio.TestTools.UnitTesting; 7 | 8 | namespace Mapster.Tests 9 | { 10 | [TestClass] 11 | public class WhenCompilingConfig 12 | { 13 | [TestInitialize] 14 | public void Setup() 15 | { 16 | TypeAdapterConfig.GlobalSettings.Clear(); 17 | } 18 | 19 | [TestMethod] 20 | public void Compile_Success_When_Contain_Collection() 21 | { 22 | TypeAdapterConfig.ForType(); 23 | 24 | //Validate globally 25 | TypeAdapterConfig.ForType() 26 | .Map(d => d.DestItems, s => s.SrcItems); 27 | 28 | TypeAdapterConfig.GlobalSettings.Compile(); 29 | } 30 | 31 | public class MainSrc 32 | { 33 | public int SrcId { get; set; } 34 | public List SrcItems { get; set; } 35 | } 36 | public class MainDest 37 | { 38 | public int DestId { get; set; } 39 | public List DestItems { get; set; } 40 | } 41 | public class SrcItem 42 | { 43 | public int ItemId { get; set; } 44 | public string StringData { get; set; } 45 | } 46 | public class DestItem 47 | { 48 | public int ItemId { get; set; } 49 | public string StringData { get; set; } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenConvertingFromObjects.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.VisualStudio.TestTools.UnitTesting; 7 | using Shouldly; 8 | 9 | namespace Mapster.Tests 10 | { 11 | [TestClass] 12 | public class WhenConvertingFromObjects 13 | { 14 | 15 | #region TestClasses 16 | 17 | public class SimplePoco 18 | { 19 | public int Int32 { get; set; } 20 | public long Int64 { get; set; } 21 | } 22 | 23 | #endregion 24 | 25 | [TestMethod] 26 | public void Int32_In_Object_Is_Converted_To_Int64() 27 | { 28 | var dictionaryData = new Dictionary 29 | { 30 | { "Int32", 32 }, 31 | { "Int64", 64 } 32 | }; 33 | 34 | var poco = dictionaryData.Adapt(); 35 | poco.Int32.ShouldBe(32); 36 | poco.Int64.ShouldBe(64L); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenIgnoreMapping.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using Newtonsoft.Json; 4 | using Shouldly; 5 | 6 | namespace Mapster.Tests 7 | { 8 | [TestClass] 9 | public class WhenIgnoreMapping 10 | { 11 | [TestInitialize] 12 | public void Setup() 13 | { 14 | TypeAdapterConfig.GlobalSettings.Clear(); 15 | } 16 | 17 | [TestMethod] 18 | public void TestIgnore() 19 | { 20 | TypeAdapterConfig.NewConfig() 21 | .TwoWays() 22 | .Ignore(it => it.Name); 23 | 24 | var poco = new Poco { Id = Guid.NewGuid(), Name = "test" }; 25 | var dto = poco.Adapt(); 26 | 27 | dto.Id.ShouldBe(poco.Id); 28 | dto.Name.ShouldBeNull(); 29 | 30 | dto.Name = "bar"; 31 | var poco2 = dto.Adapt(); 32 | 33 | poco2.Id.ShouldBe(dto.Id); 34 | poco2.Name.ShouldBeNull(); 35 | } 36 | 37 | [TestMethod] 38 | public void TestIgnoreMember() 39 | { 40 | TypeAdapterConfig.NewConfig() 41 | .TwoWays() 42 | .IgnoreMember((member, side) => 43 | member.GetCustomAttribute() != null && side == MemberSide.Destination); 44 | 45 | var poco = new Poco { Id = Guid.NewGuid(), Name = "test" }; 46 | var dto = poco.Adapt(); 47 | 48 | dto.Id.ShouldBe(poco.Id); 49 | dto.Name.ShouldBeNull(); 50 | 51 | dto.Name = "bar"; 52 | var poco2 = dto.Adapt(); 53 | 54 | poco2.Id.ShouldBe(dto.Id); 55 | poco2.Name.ShouldBeNull(); 56 | } 57 | 58 | public class Poco 59 | { 60 | public Guid Id { get; set; } 61 | public string Name { get; set; } 62 | } 63 | public class Dto 64 | { 65 | public Guid Id { get; set; } 66 | 67 | [JsonIgnore] 68 | public string Name { get; set; } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenIgnoreWithAttribute.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Shouldly; 3 | 4 | namespace Mapster.Tests 5 | { 6 | [TestClass] 7 | public class WhenIgnoreWithAttribute 8 | { 9 | [TestMethod] 10 | public void TestSource() 11 | { 12 | var poco = new Poco 13 | { 14 | Id = "Id", 15 | Prop1 = "Prop1", 16 | Prop2 = "Prop2", 17 | Prop3 = "Prop3" 18 | }; 19 | var dto = poco.Adapt(); 20 | dto.Prop1.ShouldBeNull(); 21 | dto.Prop2.ShouldBeNull(); 22 | dto.Prop3.ShouldBe(poco.Prop3); 23 | } 24 | 25 | [TestMethod] 26 | public void TestDest() 27 | { 28 | var dto = new Dto 29 | { 30 | Id = "Id", 31 | Prop1 = "Prop1", 32 | Prop2 = "Prop2", 33 | Prop3 = "Prop3" 34 | }; 35 | var poco = dto.Adapt(); 36 | poco.Prop1.ShouldBeNull(); 37 | poco.Prop2.ShouldBe(dto.Prop2); 38 | poco.Prop3.ShouldBeNull(); 39 | } 40 | 41 | public class Poco 42 | { 43 | public string Id { get; set; } 44 | 45 | [AdaptIgnore] 46 | public string Prop1 { get; set; } 47 | 48 | [AdaptIgnore(MemberSide.Source)] 49 | public string Prop2 { get; set; } 50 | 51 | [AdaptIgnore(MemberSide.Destination)] 52 | public string Prop3 { get; set; } 53 | } 54 | public class Dto 55 | { 56 | public string Id { get; set; } 57 | public string Prop1 { get; set; } 58 | public string Prop2 { get; set; } 59 | public string Prop3 { get; set; } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenIgnoringNonMapped.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Shouldly; 3 | using System; 4 | 5 | namespace Mapster.Tests 6 | { 7 | [TestClass] 8 | public class WhenIgnoringNonMapped 9 | { 10 | [TestMethod] 11 | public void Should_Ignore_Non_Mapped() 12 | { 13 | TypeAdapterConfig.NewConfig() 14 | .Map(dest => dest.Id, src => src.Id) 15 | .IgnoreNonMapped(true) 16 | .Compile(); 17 | 18 | var poco = new SimplePoco 19 | { 20 | Id = Guid.NewGuid(), 21 | Name1 = "Name1", 22 | Name2 = "Name2", 23 | Name3 = "Name3" 24 | }; 25 | 26 | var dto = poco.Adapt(); 27 | 28 | dto.Id.ShouldBe(poco.Id); 29 | dto.Name1.ShouldBeNull(); 30 | dto.Name2.ShouldBeNull(); 31 | dto.Name3.ShouldBeNull(); 32 | } 33 | 34 | #region test classes 35 | public class SimplePoco 36 | { 37 | public Guid Id { get; set; } 38 | public string Name1 { get; set; } 39 | public string Name2 { get; set; } 40 | public string Name3 { get; set; } 41 | } 42 | 43 | public class SimpleDto 44 | { 45 | public Guid Id { get; set; } 46 | public string Name1 { get; set; } 47 | public string Name2 { get; set; } 48 | public string Name3 { get; set; } 49 | } 50 | #endregion 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenMappingDerived.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Shouldly; 3 | 4 | namespace Mapster.Tests 5 | { 6 | [TestClass] 7 | public class WhenMappingDerived 8 | { 9 | [TestCleanup] 10 | public void TestCleanup() 11 | { 12 | TypeAdapterConfig.GlobalSettings.Clear(); 13 | } 14 | 15 | [TestMethod] 16 | public void WhenCompilingConfigDerivedWithoutMembers() 17 | { 18 | //Arrange 19 | var config = TypeAdapterConfig.NewConfig() 20 | .ConstructUsing(entity => new DerivedDto(entity.Id)) 21 | .Ignore(domain => domain.Id) 22 | ; 23 | 24 | //Act && Assert 25 | Should.NotThrow(() => config.Compile()); 26 | } 27 | 28 | [TestMethod] 29 | public void WhenMappingDerivedWithoutMembers() 30 | { 31 | //Arrange 32 | var inputEntity = new Entity {Id = 2L}; 33 | 34 | var config = TypeAdapterConfig.NewConfig() 35 | .ConstructUsing(entity => new DerivedDto(entity.Id)) 36 | .Ignore(domain => domain.Id) 37 | ; 38 | config.Compile(); 39 | //Act 40 | var result = TypeAdapter.Adapt(inputEntity); 41 | 42 | //Assert 43 | Assert.IsNotNull(result); 44 | Assert.AreEqual(inputEntity.Id, result.Id); 45 | } 46 | 47 | internal class BaseDto 48 | { 49 | public long Id { get; set; } 50 | 51 | protected BaseDto(long id) 52 | { 53 | Id = id; 54 | } 55 | } 56 | 57 | internal class Entity 58 | { 59 | public long Id { get; set; } 60 | } 61 | 62 | internal class DerivedDto : BaseDto 63 | { 64 | public DerivedDto(long id) : base(id) { } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenMappingEntityWithOnlyPrimitives.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Assert = Microsoft.VisualStudio.TestTools.UnitTesting.Assert; 3 | 4 | namespace Mapster.Tests 5 | { 6 | 7 | [TestClass] 8 | public class WhenMappingEntityWithOnlyPrimitives 9 | { 10 | #region Classes 11 | 12 | public class Customer 13 | { 14 | public int Id { get; set; } 15 | public string Name { get; set; } 16 | public decimal Credit { get; set; } 17 | public bool IsActive { get; set; } 18 | public char DriverLicenceType { get; set; } 19 | public double? Debit { get; set; } 20 | public string City { get; set; } 21 | public string Country { get; set; } 22 | } 23 | 24 | public class CustomerDTO 25 | { 26 | public int Id { get; set; } 27 | public string Name { get; set; } 28 | public decimal Credit { get; set; } 29 | public bool IsActive { get; set; } 30 | public char DriverLicenceType { get; set; } 31 | public double? Debit { get; set; } 32 | } 33 | 34 | public Customer GetCustomer() 35 | { 36 | return new Customer() 37 | { 38 | City = "istanbul", 39 | Country = "turkey", 40 | Credit = 1542, 41 | DriverLicenceType = 'B', 42 | Id = 1, 43 | Debit = 100, 44 | IsActive = true, 45 | Name = "Timuçin" 46 | }; 47 | } 48 | 49 | #endregion 50 | 51 | [TestMethod] 52 | public void ConvertPrimitiveEntityToDto() 53 | { 54 | var dto = TypeAdapter.Adapt(GetCustomer()); 55 | 56 | Assert.IsNotNull(dto); 57 | Assert.IsTrue(dto.Id == 1 && 58 | dto.Name == "Timuçin" && 59 | dto.Credit == 1542 && 60 | dto.IsActive && 61 | dto.DriverLicenceType == 'B' && 62 | dto.Debit == 100 63 | ); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenMappingIEnumerableClass.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Shouldly; 3 | using System; 4 | using System.Collections; 5 | 6 | namespace Mapster.Tests 7 | { 8 | [TestClass] 9 | public class WhenMappingIEnumerableClasses 10 | { 11 | public class ClassA 12 | { 13 | public int Id { get; set; } 14 | } 15 | 16 | public class ClassB : IEnumerable 17 | { 18 | public int Id { get; set; } 19 | 20 | public IEnumerator GetEnumerator() 21 | { 22 | throw new NotImplementedException(); 23 | } 24 | } 25 | 26 | [TestMethod] 27 | public void Map_To_IEnumerable_Class_Should_Pass() 28 | { 29 | ClassA classA = new ClassA() 30 | { 31 | Id = 123 32 | }; 33 | 34 | ClassB classB = classA.Adapt(); 35 | classB.Id.ShouldBe(classA.Id); 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenMappingIgnoreNullValues.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace Mapster.Tests 5 | { 6 | [TestClass] 7 | public class WhenMappingIgnoreNullValues 8 | { 9 | [TestMethod] 10 | public void Map() 11 | { 12 | TypeAdapterConfig.GlobalSettings.Clear(); 13 | TypeAdapterConfig.GlobalSettings.NewConfig() 14 | .IgnoreNullValues(true) 15 | .Compile(); 16 | 17 | var source = new SourceClass(); 18 | var dest = source.Adapt(); 19 | 20 | Assert.AreEqual("Hello", dest.Title); 21 | Assert.IsNotNull(dest.Sub); 22 | Assert.IsNotNull(dest.List); 23 | } 24 | 25 | [TestMethod] 26 | public void Map_To_Target() 27 | { 28 | TypeAdapterConfig.GlobalSettings.Clear(); 29 | TypeAdapterConfig.GlobalSettings.NewConfig() 30 | .IgnoreNullValues(true) 31 | .Compile(); 32 | 33 | var source = new SourceClass(); 34 | var dest = source.Adapt(new DestClass()); 35 | 36 | Assert.AreEqual("Hello", dest.Title); 37 | Assert.IsNotNull(dest.Sub); 38 | Assert.IsNotNull(dest.List); 39 | } 40 | 41 | public class DestClass 42 | { 43 | public string Title { get; set; } 44 | public List List { get; set; } 45 | public SubClass Sub { get; set; } 46 | 47 | public DestClass() 48 | { 49 | List = new List(); 50 | Sub = new SubClass(); 51 | Title = "Hello"; 52 | } 53 | } 54 | 55 | public class SourceClass 56 | { 57 | public string Title { get; set; } 58 | public List List { get; set; } 59 | public SubClass Sub { get; set; } 60 | } 61 | 62 | public class SubClass 63 | { 64 | public string SubName { get; set; } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenMappingMultipleSources.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Shouldly; 3 | 4 | namespace Mapster.Tests 5 | { 6 | [TestClass] 7 | public class WhenMappingMultipleSources 8 | { 9 | [TestMethod] 10 | public void TestNestedSources() 11 | { 12 | TypeAdapterConfig.NewConfig() 13 | .Map(dest => dest, src => src.Details); 14 | 15 | var dto = new Dto 16 | { 17 | Name = "foo", 18 | Details = new SubDto {Extras = "bar"} 19 | }; 20 | var poco = dto.Adapt(); 21 | poco.Name.ShouldBe(dto.Name); 22 | poco.Extras.ShouldBe(dto.Details.Extras); 23 | } 24 | 25 | [TestMethod] 26 | public void TestTupleSources() 27 | { 28 | TypeAdapterConfig<(Dto, SubDto), Poco>.NewConfig() 29 | .Map(dest => dest, src => src.Item1) 30 | .Map(dest => dest, src => src.Item2); 31 | 32 | var dto = new Dto {Name = "foo"}; 33 | var sub = new SubDto {Extras = "bar"}; 34 | 35 | var poco = (dto, sub).Adapt(); 36 | poco.Name.ShouldBe(dto.Name); 37 | poco.Extras.ShouldBe(sub.Extras); 38 | } 39 | 40 | public class SubDto 41 | { 42 | public string Extras { get; set; } 43 | } 44 | public class Dto 45 | { 46 | public string Name { get; set; } 47 | public SubDto Details { get; set; } 48 | } 49 | public class Poco 50 | { 51 | public string Name { get; set; } 52 | public string Extras { get; set; } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenMappingStruct.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Shouldly; 3 | 4 | namespace Mapster.Tests 5 | { 6 | [TestClass] 7 | public class WhenMappingStruct 8 | { 9 | class MyClassA 10 | { 11 | public MyStruct MyStruct { get; set; } 12 | } 13 | class MyClassB 14 | { 15 | public MyStruct MyStruct { get; set; } 16 | } 17 | 18 | struct MyStruct 19 | { 20 | public MyStruct(string prop) : this() 21 | { 22 | Property = prop; 23 | } 24 | 25 | public string Property { get; set; } 26 | } 27 | 28 | [TestMethod] 29 | public void TestMapping() 30 | { 31 | var a = new MyClassA(); 32 | 33 | a.MyStruct = new MyStruct("A"); 34 | 35 | var b = a.Adapt(); 36 | 37 | b.MyStruct.Property.ShouldBe("A"); 38 | } 39 | 40 | [TestMethod] 41 | public void TestMappingToTarget() 42 | { 43 | var a = new MyClassA(); 44 | var b = new MyClassB(); 45 | 46 | a.MyStruct = new MyStruct("A"); 47 | 48 | a.Adapt(b); 49 | 50 | b.MyStruct.Property.ShouldBe("A"); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenMappingStructRegression.cs: -------------------------------------------------------------------------------- 1 | using Mapster; 2 | using MapsterMapper; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using Shouldly; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using static Mapster.Tests.WhenMappingStructRegression; 11 | 12 | namespace Mapster.Tests 13 | { 14 | /// 15 | /// Regression tests for https://github.com/MapsterMapper/Mapster/issues/510 16 | /// 17 | [TestClass] 18 | public class WhenMappingStructRegression 19 | { 20 | public struct SourceClass 21 | { 22 | public string Name { get; set; } 23 | } 24 | 25 | public struct SourceStruct 26 | { 27 | public string Name { get; set; } 28 | } 29 | public struct DestinationStruct 30 | { 31 | public string Name { get; set; } 32 | 33 | public string Ignore { get; set; } 34 | } 35 | 36 | [TestMethod] 37 | public void TestMapStructToExistingStruct() 38 | { 39 | 40 | TypeAdapterConfig 41 | .ForType() 42 | .Ignore(s => s.Ignore); 43 | 44 | var source = new SourceStruct 45 | { 46 | Name = "Some Name", 47 | }; 48 | var dest = new DestinationStruct 49 | { 50 | Ignore = "Ignored property", 51 | }; 52 | dest = source.Adapt(dest); 53 | 54 | dest.Ignore.ShouldBe("Ignored property"); 55 | dest.Name.ShouldBe("Some Name"); 56 | } 57 | 58 | [TestMethod] 59 | public void TestMapClassToExistingStruct() 60 | { 61 | 62 | TypeAdapterConfig 63 | .ForType() 64 | .Ignore(s => s.Ignore); 65 | 66 | var source = new SourceClass 67 | { 68 | Name = "Some Name", 69 | }; 70 | var dest = new DestinationStruct 71 | { 72 | Ignore = "Ignored property", 73 | }; 74 | dest = source.Adapt(dest); 75 | 76 | dest.Ignore.ShouldBe("Ignored property"); 77 | dest.Name.ShouldBe("Some Name"); 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenMappingToTarget.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using Shouldly; 4 | 5 | namespace Mapster.Tests 6 | { 7 | [TestClass] 8 | public class WhenMappingToTarget 9 | { 10 | [TestMethod] 11 | public void MappingToTarget_With_SameList() 12 | { 13 | var a = new Foo { A = 1, List = new List { 1, 2, 3 } }; 14 | var b = new Bar { A = 2, List = a.List }; 15 | 16 | a.Adapt(b); 17 | 18 | b.A.ShouldBe(1); 19 | b.List.ShouldBe(new List { 1, 2, 3 }); 20 | } 21 | 22 | [TestMethod] 23 | public void MappingToTarget_With_NullDestinationList_Create_New() 24 | { 25 | var a = new Foo { List = new List { 1, 2, 3, } }; 26 | var b = new Bar { List = null }; 27 | 28 | a.Adapt(b); 29 | b.List.ShouldBe(new List { 1, 2, 3, }); 30 | } 31 | 32 | public class Foo 33 | { 34 | public double A { get; set; } 35 | public List List { get; set; } 36 | } 37 | 38 | public class Bar 39 | { 40 | public double A { get; set; } 41 | public List List { get; set; } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenMappingWithAdaptIgnoreRegression.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Shouldly; 3 | using System; 4 | 5 | namespace Mapster.Tests 6 | { 7 | /// 8 | /// Regression test for https://github.com/MapsterMapper/Mapster/issues/450 9 | /// 10 | [TestClass] 11 | public class WhenMappingWithAdaptIgnoreRegression 12 | { 13 | public abstract class Base 14 | { 15 | public DateTime CreatedOn { get; private set; } 16 | 17 | public DateTime UpdatedOn { get; set; } 18 | 19 | public int State { get; set; } 20 | 21 | public Base() 22 | { 23 | CreatedOn = DateTime.UtcNow; 24 | UpdatedOn = DateTime.UtcNow; 25 | State = 1; 26 | } 27 | } 28 | 29 | public class Poco : Base 30 | { 31 | public string Name { get; set; } 32 | } 33 | 34 | public class Dto 35 | { 36 | public string Name { get; set; } 37 | } 38 | 39 | [TestMethod] 40 | public void TestMapStructToExistingStruct() 41 | { 42 | TypeAdapterConfig 43 | .ForType() 44 | .Ignore(s => s.State) 45 | .Ignore(s => s.CreatedOn) 46 | .Ignore(s => s.UpdatedOn); 47 | 48 | var destination = new Poco() { Name = "Destination", State = 2 }; 49 | var source = new Dto() { Name = "Source" }; 50 | var result = source.Adapt(destination); 51 | result.State.ShouldBe(2); 52 | result.Name.ShouldBe("Source"); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenMappingWithGetMethod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.VisualStudio.TestTools.UnitTesting; 7 | using Shouldly; 8 | 9 | namespace Mapster.Tests 10 | { 11 | [TestClass] 12 | public class WhenMappingWithGetMethod 13 | { 14 | [TestMethod] 15 | public void Should_Copy_Value_From_Get_Method() 16 | { 17 | var poco = new Poco {FirstName = "Foo", LastName = "Bar"}; 18 | var dto = poco.Adapt(); 19 | dto.FullName.ShouldBe("Foo Bar"); 20 | } 21 | 22 | [TestMethod] 23 | public void Should_Ignore_GetType() 24 | { 25 | var poco = new Poco { FirstName = "Foo", LastName = "Bar" }; 26 | var dto = poco.Adapt(); 27 | dto.Type.ShouldBeNull(); 28 | } 29 | 30 | [TestMethod] 31 | public void Allow_GetType_If_Property_Is_Type() 32 | { 33 | var poco = new Poco { FirstName = "Foo", LastName = "Bar" }; 34 | var dto = poco.Adapt(); 35 | dto.Type.ShouldBe(typeof(Poco)); 36 | } 37 | 38 | #region TestClasses 39 | 40 | public class Poco 41 | { 42 | public string FirstName { get; set; } 43 | public string LastName { get; set; } 44 | public string GetFullName() => FirstName + " " + LastName; 45 | } 46 | 47 | public class Dto 48 | { 49 | public string FullName { get; set; } 50 | } 51 | 52 | public class Dto2 53 | { 54 | public string FirstName { get; set; } 55 | public string LastName { get; set; } 56 | public string Type { get; set; } 57 | } 58 | 59 | public class Dto3 60 | { 61 | public string FirstName { get; set; } 62 | public string LastName { get; set; } 63 | public Type Type { get; set; } 64 | } 65 | 66 | #endregion 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenMappingWithOpenGenerics.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Shouldly; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Mapster.Tests 10 | { 11 | [TestClass] 12 | public class WhenMappingWithOpenGenerics 13 | { 14 | [TestMethod] 15 | public void Map_With_Open_Generics() 16 | { 17 | TypeAdapterConfig.GlobalSettings.ForType(typeof(GenericPoco<>), typeof(GenericDto<>)) 18 | .Map("value", "Value"); 19 | 20 | var poco = new GenericPoco { Value = 123 }; 21 | var dto = poco.Adapt>(); 22 | dto.value.ShouldBe(poco.Value); 23 | } 24 | 25 | [TestMethod] 26 | public void Setting_From_OpenGeneric_Has_No_SideEffect() 27 | { 28 | var config = new TypeAdapterConfig(); 29 | config 30 | .NewConfig(typeof(A<>), typeof(B<>)) 31 | .Map("BProperty", "AProperty"); 32 | 33 | var a = new A { AProperty = "A" }; 34 | var c = new C { BProperty = "C" }; 35 | var b = a.Adapt>(config); // successful mapping 36 | var cCopy = c.Adapt(config); 37 | } 38 | 39 | public class GenericPoco 40 | { 41 | public T Value { get; set; } 42 | } 43 | 44 | public class GenericDto 45 | { 46 | public T value { get; set; } 47 | } 48 | 49 | class A { public string AProperty { get; set; } } 50 | 51 | class B { public string BProperty { get; set; } } 52 | 53 | class C { public string BProperty { get; set; } } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenMappingWithParametersOnRecordsRegression.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Shouldly; 3 | using System; 4 | 5 | namespace Mapster.Tests 6 | { 7 | /// 8 | /// This turned out not to be a bug, but I left the regression test here anyway 9 | /// 10 | [TestClass] 11 | public class WhenMappingWithParametersOnRecordsRegression 12 | { 13 | record Class1(string Title); 14 | record Class2(int Id, string Title); 15 | 16 | [TestMethod] 17 | public void TestMapRecordsWithParameters() 18 | { 19 | TypeAdapterConfig.NewConfig() 20 | .Map(dest => dest.Id, 21 | src => MapContext.Current.Parameters["Id"]); 22 | 23 | var c1 = new Class1("title1"); 24 | var c2 = c1.BuildAdapter() 25 | .AddParameters("Id", 1) 26 | .AdaptToType(); 27 | 28 | c2.Id.ShouldBe(1); 29 | c2.Title.ShouldBe("title1"); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenMappingWithSecondSourceObject.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Shouldly; 3 | using System; 4 | 5 | namespace Mapster.Tests 6 | { 7 | 8 | /// 9 | /// Regression for https://github.com/MapsterMapper/Mapster/issues/485 10 | /// 11 | [TestClass] 12 | public class WhenMappingWithSecondSourceObject 13 | { 14 | public interface ISomeType 15 | { 16 | public int Id { get; set; } 17 | public string Name { get; set; } 18 | public string Address { get; set; } 19 | } 20 | public class ConcreteType1 : ISomeType 21 | { 22 | public int Id { get; set; } 23 | public string Name { get; set; } 24 | 25 | public string Address { get; set; } 26 | } 27 | 28 | public class ConcreteType2 29 | { 30 | public int Id { get; set; } 31 | public string Name { get; set; } 32 | } 33 | 34 | [TestMethod] 35 | public void TestMapFromSecondSourceObject() 36 | { 37 | var c1 = new ConcreteType1 38 | { 39 | Id = 1, 40 | Name = "Name 1", 41 | Address = "Address 1" 42 | }; 43 | 44 | var c2 = new ConcreteType2 45 | { 46 | Id = 2, 47 | Name = "Name 2" 48 | }; 49 | 50 | var generatedType = c1.Adapt(); 51 | 52 | generatedType.Id.ShouldBe(1); 53 | generatedType.Name.ShouldBe("Name 1"); 54 | generatedType.Address.ShouldBe("Address 1"); 55 | 56 | generatedType = c2.Adapt(generatedType); 57 | 58 | generatedType.Id.ShouldBe(2); 59 | generatedType.Name.ShouldBe("Name 2"); 60 | generatedType.Address.ShouldBe("Address 1"); 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenPassingRuntimeValue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using Shouldly; 4 | 5 | namespace Mapster.Tests 6 | { 7 | [TestClass] 8 | public class WhenPassingRuntimeValue 9 | { 10 | [TestMethod] 11 | public void Passing_Runtime_Value() 12 | { 13 | TypeAdapterConfig.NewConfig() 14 | .Map(dest => dest.CreatedBy, 15 | src => MapContext.Current.Parameters["user"]); 16 | 17 | var poco = new SimplePoco 18 | { 19 | Id = Guid.NewGuid(), 20 | Name = "test", 21 | }; 22 | var dto = poco.BuildAdapter() 23 | .AddParameters("user", this.User) 24 | .AdaptToType(); 25 | 26 | dto.CreatedBy.ShouldBe(this.User); 27 | } 28 | 29 | private string User { get; } = Guid.NewGuid().ToString("N"); 30 | 31 | public class SimplePoco 32 | { 33 | public Guid Id { get; set; } 34 | public string Name { get; set; } 35 | } 36 | 37 | public class SimpleDto 38 | { 39 | public Guid Id { get; set; } 40 | public string Name { get; set; } 41 | public string CreatedBy { get; set; } 42 | } 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenScanningForRegisters.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Reflection; 4 | using Mapster.Models; 5 | using Mapster.Tests.Classes; 6 | using Microsoft.VisualStudio.TestTools.UnitTesting; 7 | using Shouldly; 8 | 9 | namespace Mapster.Tests 10 | { 11 | [TestClass] 12 | public class WhenScanningForRegisters 13 | { 14 | [TestMethod] 15 | public void Registers_Are_Found() 16 | { 17 | var config = new TypeAdapterConfig(); 18 | IList registers = config.Scan(Assembly.GetExecutingAssembly()); 19 | registers.Count.ShouldBe(2); 20 | 21 | var typeTuples = config.RuleMap.Keys.ToList(); 22 | 23 | typeTuples.Any(x => x.Equals(new TypeTuple(typeof (Customer), typeof (CustomerDTO)))).ShouldBeTrue(); 24 | typeTuples.Any(x => x.Equals(new TypeTuple(typeof (Product), typeof (ProductDTO)))).ShouldBeTrue(); 25 | typeTuples.Any(x => x.Equals(new TypeTuple(typeof (Person), typeof (PersonDTO)))).ShouldBeTrue(); 26 | 27 | typeTuples.Any(x => x.Equals(new TypeTuple(typeof (PersonDTO), typeof (Person)))).ShouldBeFalse(); 28 | } 29 | 30 | public class TestRegister : IRegister 31 | { 32 | public void Register(TypeAdapterConfig config) 33 | { 34 | config.NewConfig(); 35 | config.NewConfig(); 36 | 37 | config.ForType() 38 | .Map(dest => dest.Title, src => src.Title + "_AppendSomething!"); 39 | } 40 | } 41 | 42 | public class TestRegister2 : IRegister 43 | { 44 | public void Register(TypeAdapterConfig config) 45 | { 46 | config.ForType(); 47 | } 48 | } 49 | 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenSettingMapToTargetWith.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Shouldly; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Mapster.Tests 10 | { 11 | [TestClass] 12 | public class WhenSettingMapToTargetWith 13 | { 14 | [TestMethod] 15 | public void MapToTargetWith_Should_Work_With_Adapt_To_Target() 16 | { 17 | var a = new Foo { A = 1 }; 18 | var b = new Bar { A = 2 }; 19 | 20 | var config = new TypeAdapterConfig(); 21 | config.Default.ShallowCopyForSameType(true); 22 | 23 | config.NewConfig().MapToTargetWith((x, y) => 5); 24 | a.Adapt(b, config); 25 | b.A.ShouldBe(5); 26 | } 27 | 28 | [TestMethod] 29 | public void MapWith_Should_Work_With_Adapt_To_Target() 30 | { 31 | var a = new List {1, 2, 3}; 32 | 33 | var config = new TypeAdapterConfig(); 34 | config.Default.ShallowCopyForSameType(true); 35 | 36 | config.NewConfig().MapWith(_ => 5); 37 | var b = a.Adapt>(config); 38 | b.ShouldBe(new List{ 5, 5, 5}); 39 | } 40 | 41 | [TestMethod] 42 | public void MapWith_Should_Work_With_Adapt_To_Target_For_Collection() 43 | { 44 | var a = new List {1, 2, 3}; 45 | 46 | var config = new TypeAdapterConfig(); 47 | config.Default.ShallowCopyForSameType(true); 48 | 49 | config.NewConfig, List>().MapWith(_ => new List{ 5, 5, 5}); 50 | var b = a.Adapt>(config); 51 | b.ShouldBe(new List{ 5, 5, 5}); 52 | } 53 | 54 | internal class Foo 55 | { 56 | public double A { get; set; } 57 | } 58 | 59 | internal class Bar 60 | { 61 | public double A { get; set; } 62 | } 63 | 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenUsingAttribute.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Shouldly; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Mapster.Tests 10 | { 11 | [TestClass] 12 | public class WhenUsingAttribute 13 | { 14 | [TestMethod] 15 | public void Using_Attributes() 16 | { 17 | var id = Guid.NewGuid(); 18 | var poco = new SimplePoco(id) { Name = "test" }; 19 | var dto = poco.Adapt(); 20 | dto.Id.ShouldBe(id); 21 | dto.Name.ShouldBeNull(); 22 | } 23 | 24 | [TestMethod] 25 | public void Specify_MemberSide() 26 | { 27 | var user = new User {UserIdentification = 123}; 28 | var dto = user.Adapt(); 29 | var info = dto.Adapt(); 30 | info.UserId.ShouldBe(123); 31 | } 32 | 33 | public class SimplePoco 34 | { 35 | public SimplePoco(Guid id) { this.id = id; } 36 | 37 | [AdaptMember("Id")] 38 | private Guid id { get; } 39 | 40 | [AdaptIgnore] 41 | public string Name { get; set; } 42 | } 43 | 44 | public class SimpleDto 45 | { 46 | public Guid Id { get; set; } 47 | public string Name { get; set; } 48 | } 49 | 50 | public class User 51 | { 52 | public int UserIdentification {get; set;} 53 | } 54 | 55 | public class UserDto 56 | { 57 | [AdaptMember("UserIdentification", MemberSide.Destination)] 58 | public int UserId {get; set;} 59 | } 60 | 61 | public class UserInfo 62 | { 63 | public int UserId {get; set;} 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenUsingAttributeWithNameMatchingStrategy.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using Shouldly; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Mapster.Tests 10 | { 11 | [TestClass] 12 | public class WhenUsingAttributeWithNameMatchingStrategy 13 | { 14 | [TestMethod] 15 | public void Using_Attributes_With_NameMatchingStrategy() 16 | { 17 | TypeAdapterConfig.GlobalSettings.Default.NameMatchingStrategy(NameMatchingStrategy.IgnoreCase); 18 | 19 | var id = Guid.NewGuid(); 20 | var poco = new SimplePoco(id) { Name = "test" }; 21 | var dto = poco.Adapt(); 22 | dto.IdCode.ShouldBe(id); 23 | dto.Name.ShouldBeNull(); 24 | } 25 | 26 | public class SimplePoco 27 | { 28 | public SimplePoco(Guid id) { this.id = id; } 29 | 30 | [AdaptMember("IdCode")] 31 | private Guid id { get; } 32 | 33 | [AdaptIgnore] 34 | public string Name { get; set; } 35 | } 36 | 37 | public class SimpleDto 38 | { 39 | public Guid IdCode { get; set; } 40 | public string Name { get; set; } 41 | } 42 | 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenUsingConverterFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using Shouldly; 4 | 5 | namespace Mapster.Tests 6 | { 7 | [TestClass] 8 | public class WhenUsingConverterFactory 9 | { 10 | 11 | [TestMethod] 12 | public void Custom_Mapping_From_String_To_Char_Array() 13 | { 14 | TypeAdapterConfig.NewConfig() 15 | .MapWith(str => str.ToCharArray()); 16 | 17 | var chars = TypeAdapter.Adapt("Hello"); 18 | 19 | chars.Length.ShouldBe(5); 20 | chars[0].ShouldBe('H'); 21 | chars[1].ShouldBe('e'); 22 | chars[2].ShouldBe('l'); 23 | chars[3].ShouldBe('l'); 24 | chars[4].ShouldBe('o'); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenUsingIMapFrom.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using Mapster.Utils; 5 | using MapsterMapper; 6 | using Microsoft.VisualStudio.TestTools.UnitTesting; 7 | using Shouldly; 8 | 9 | namespace Mapster.Tests; 10 | 11 | [TestClass] 12 | public class WhenUsingIMapFrom 13 | { 14 | private readonly Mapper _mapper; 15 | 16 | public WhenUsingIMapFrom() 17 | { 18 | _mapper = new Mapper(); 19 | var types = new List 20 | { 21 | typeof(SourceModel), 22 | typeof(InheritedDestinationModel), 23 | typeof(DestinationModel) 24 | }; 25 | TypeAdapterConfig.GlobalSettings.ScanInheritedTypes(types); 26 | } 27 | 28 | [TestMethod] 29 | public void TestIMapFrom_WhenMethodIsNotImplemented() 30 | { 31 | var source = new SourceModel(DesireValues.Text); 32 | var destination = _mapper.Map(source); 33 | destination.Type.ShouldBe(DesireValues.Text); 34 | } 35 | 36 | [TestMethod] 37 | public void TestIMapFrom_WhenMethodImplemented() 38 | { 39 | var source = new SourceModel(DesireValues.Text); 40 | var destination = _mapper.Map(source); 41 | destination.Type.ShouldBe(DesireValues.Text); 42 | destination.Value.ShouldBe(9); 43 | } 44 | } 45 | 46 | internal static class DesireValues 47 | { 48 | internal const string Text = "Test"; 49 | internal const int Number = 9; 50 | } 51 | 52 | public class SourceModel 53 | { 54 | public SourceModel(string type) 55 | { 56 | Type = type; 57 | } 58 | 59 | public string Type { get; set; } 60 | } 61 | 62 | public class InheritedDestinationModel : IMapFrom 63 | { 64 | public string Type { get; set; } 65 | public int Value { get; set; } 66 | 67 | public void ConfigureMapping(TypeAdapterConfig config) 68 | { 69 | config.NewConfig() 70 | .Map(dest => dest.Value, _ => DesireValues.Number); 71 | } 72 | } 73 | 74 | public class DestinationModel : IMapFrom 75 | { 76 | public string Type { get; set; } 77 | } -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenUsingIMapFromWrong.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using Mapster.Utils; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using Shouldly; 6 | 7 | namespace Mapster.Tests; 8 | 9 | [TestClass] 10 | public class WhenUsingIMapFromWrong 11 | { 12 | [TestMethod] 13 | public void TestIMapFrom_WhenMethodImplementedWrong_ShouldRaiseException() 14 | { 15 | Should.Throw(() => 16 | { 17 | TypeAdapterConfig.GlobalSettings.ScanInheritedTypes(Assembly.GetExecutingAssembly()); 18 | }); 19 | } 20 | } 21 | 22 | public class WrongInheritedDestinationModel : IMapFrom 23 | { 24 | public string Type { get; set; } 25 | public int Value { get; set; } 26 | 27 | public void ConfigureMapping() 28 | { 29 | TypeAdapterConfig.GlobalSettings 30 | .NewConfig() 31 | .Map(dest => dest.Value, _ => DesireValues.Number); 32 | } 33 | } -------------------------------------------------------------------------------- /src/Mapster.Tests/WhenUsingRuleBasedSetting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | using Shouldly; 4 | 5 | namespace Mapster.Tests 6 | { 7 | [TestClass] 8 | public class WhenUsingRuleBasedSetting 9 | { 10 | 11 | [TestMethod] 12 | public void Rule_Base_Testing() 13 | { 14 | var config = new TypeAdapterConfig(); 15 | config.When((srcType, destType, mapType) => srcType == destType) 16 | .Ignore("Id"); 17 | 18 | var simplePoco = new SimplePoco {Id = Guid.NewGuid(), Name = "TestName"}; 19 | 20 | var dto = TypeAdapter.Adapt(simplePoco, config); 21 | 22 | dto.Id.ShouldBe(Guid.Empty); 23 | dto.Name.ShouldBe(simplePoco.Name); 24 | } 25 | 26 | #region TestClasses 27 | 28 | public class SimplePoco 29 | { 30 | public Guid Id { get; set; } 31 | public string Name { get; set; } 32 | } 33 | 34 | #endregion 35 | 36 | 37 | } 38 | } -------------------------------------------------------------------------------- /src/Mapster.Tests/mock.keys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.Tests/mock.keys -------------------------------------------------------------------------------- /src/Mapster.Tool.Tests/.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "mapster.tool": { 6 | "version": "8.3.0", 7 | "commands": [ 8 | "dotnet-mapster" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Mapster.Tool.Tests/Mappers/IUserMapper.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | namespace Mapster.Tool.Tests.Mappers; 4 | 5 | [Mapper] 6 | public interface IUserMapper 7 | { 8 | Expression> UserProjection { get; } 9 | _UserDto MapTo(_User user); 10 | _UserDto MapTo(_User user, _UserDto userDto); 11 | } -------------------------------------------------------------------------------- /src/Mapster.Tool.Tests/Mappers/UserMapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using Mapster.Tool.Tests; 4 | using Mapster.Tool.Tests.Mappers; 5 | 6 | namespace Mapster.Tool.Tests.Mappers 7 | { 8 | public partial class UserMapper : IUserMapper 9 | { 10 | public Expression> UserProjection => p1 => new _UserDto() 11 | { 12 | Id = p1.Id, 13 | Name = p1.Name 14 | }; 15 | public _UserDto MapTo(_User p2) 16 | { 17 | return p2 == null ? null : new _UserDto() 18 | { 19 | Id = p2.Id, 20 | Name = p2.Name 21 | }; 22 | } 23 | public _UserDto MapTo(_User p3, _UserDto p4) 24 | { 25 | if (p3 == null) 26 | { 27 | return null; 28 | } 29 | _UserDto result = p4 ?? new _UserDto(); 30 | 31 | typeof(_UserDto).GetProperty("Id").SetValue(result, (object)p3.Id); 32 | typeof(_UserDto).GetProperty("Name").SetValue(result, p3.Name); 33 | return result; 34 | 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/Mapster.Tool.Tests/TestBase.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace Mapster.Tool.Tests; 4 | 5 | public class TestBase 6 | { 7 | private readonly IServiceScopeFactory _scopeFactory; 8 | 9 | public TestBase() 10 | { 11 | var services = ConfigureServiceCollection(); 12 | using var scope = services.BuildServiceProvider().CreateScope(); 13 | _scopeFactory = scope.ServiceProvider.GetRequiredService(); 14 | } 15 | 16 | private ServiceCollection ConfigureServiceCollection() 17 | { 18 | ServiceCollection services = new(); 19 | services.Scan(selector => selector 20 | .FromCallingAssembly() 21 | .AddClasses() 22 | .AsMatchingInterface() 23 | .WithSingletonLifetime()); 24 | return services; 25 | } 26 | 27 | protected TInterface GetMappingInterface() 28 | { 29 | using var scope = _scopeFactory.CreateScope(); 30 | var service = scope.ServiceProvider.GetService(typeof(TInterface)); 31 | if (service == null) 32 | { 33 | throw new Exception($"Service of type {typeof(TInterface).Name} not found!"); 34 | } 35 | 36 | return (TInterface)service; 37 | } 38 | } -------------------------------------------------------------------------------- /src/Mapster.Tool.Tests/Usings.cs: -------------------------------------------------------------------------------- 1 | global using Xunit; -------------------------------------------------------------------------------- /src/Mapster.Tool.Tests/WhenMappingWithExistingObjectAndInitProperties.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using FluentAssertions; 3 | using Mapster.Tool.Tests.Mappers; 4 | 5 | namespace Mapster.Tool.Tests; 6 | 7 | /// 8 | /// Tests for https://github.com/MapsterMapper/Mapster/issues/536 9 | /// 10 | public class WhenMappingWithExistingObjectAndInitProperties : TestBase 11 | { 12 | [Fact] 13 | public void MapWithReflection() 14 | { 15 | TypeAdapterConfig.GlobalSettings 16 | .Scan(Assembly.GetExecutingAssembly()); 17 | 18 | var userMapper = GetMappingInterface(); 19 | var expected = "Aref"; 20 | var user = new _User { Name = expected, Id = 1 }; 21 | var dto = new _UserDto(); 22 | userMapper.MapTo(user, dto); 23 | dto.Name.Should().Be(expected); 24 | } 25 | } 26 | 27 | public class UserMappingRegister : IRegister 28 | { 29 | public void Register(TypeAdapterConfig config) 30 | { 31 | config.NewConfig<_User, _UserDto>() 32 | .MapToConstructor(true) 33 | .ConstructUsing(s => new _UserDto()); 34 | } 35 | } 36 | 37 | public class _User 38 | { 39 | public int Id { get; init; } 40 | public string Name { get; init; } 41 | } 42 | 43 | public class _UserDto 44 | { 45 | public int Id { get; init; } 46 | public string Name { get; init; } 47 | } -------------------------------------------------------------------------------- /src/Mapster.Tool/ExtensionOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using CommandLine; 3 | using CommandLine.Text; 4 | 5 | namespace Mapster.Tool 6 | { 7 | [Verb("extension", HelpText = "Generate extensions")] 8 | public class ExtensionOptions 9 | { 10 | [Option('a', "assembly", Required = true, HelpText = "Assembly to scan")] 11 | public string Assembly { get; set; } 12 | 13 | [Option('o', "output", Required = false, Default = "Models", HelpText = "Output directory.")] 14 | public string Output { get; set; } 15 | 16 | [Option('n', "namespace", Required = false, HelpText = "Namespace for extensions")] 17 | public string? Namespace { get; set; } 18 | 19 | [Option('p', "printFullTypeName", Required = false, HelpText = "Set true to print full type name")] 20 | public bool PrintFullTypeName { get; set; } 21 | 22 | [Option('b', "baseNamespace", Required = false, HelpText = "Provide base namespace to generate nested output & namespace")] 23 | public string? BaseNamespace { get; set; } 24 | 25 | [Option('s', "skipExisting", Required = false, HelpText = "Set true to skip generating already existing files")] 26 | public bool SkipExistingFiles { get; set; } 27 | 28 | [Option('N', "nullableDirective", Required = false, HelpText = "Set true to add \"#nullable enable\" to the top of generated extension files")] 29 | public bool GenerateNullableDirective { get; set; } 30 | 31 | [Usage(ApplicationAlias = "dotnet mapster extension")] 32 | public static IEnumerable Examples => 33 | new List 34 | { 35 | new Example("Generate extensions", new MapperOptions 36 | { 37 | Assembly = "/Path/To/YourAssembly.dll", 38 | Output = "Models" 39 | }) 40 | }; 41 | } 42 | } -------------------------------------------------------------------------------- /src/Mapster.Tool/MapperOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using CommandLine; 3 | using CommandLine.Text; 4 | 5 | namespace Mapster.Tool 6 | { 7 | [Verb("mapper", true, HelpText = "Generate mappers")] 8 | public class MapperOptions 9 | { 10 | [Option('a', "assembly", Required = true, HelpText = "Assembly to scan")] 11 | public string Assembly { get; set; } 12 | 13 | [Option('o', "output", Required = false, Default = "Mappers", HelpText = "Output directory.")] 14 | public string Output { get; set; } 15 | 16 | [Option('n', "namespace", Required = false, HelpText = "Namespace for mappers")] 17 | public string? Namespace { get; set; } 18 | 19 | [Option('p', "printFullTypeName", Required = false, HelpText = "Set true to print full type name")] 20 | public bool PrintFullTypeName { get; set; } 21 | 22 | [Option('b', "baseNamespace", Required = false, HelpText = "Provide base namespace to generate nested output & namespace")] 23 | public string? BaseNamespace { get; set; } 24 | 25 | [Option('s', "skipExisting", Required = false, HelpText = "Set true to skip generating already existing files")] 26 | public bool SkipExistingFiles { get; set; } 27 | 28 | [Option('N', "nullableDirective", Required = false, HelpText = "Set true to add \"#nullable enable\" to the top of generated mapper files")] 29 | public bool GenerateNullableDirective { get; set; } 30 | 31 | [Usage(ApplicationAlias = "dotnet mapster mapper")] 32 | public static IEnumerable Examples => 33 | new List 34 | { 35 | new Example("Generate mapping", new MapperOptions 36 | { 37 | Assembly = "/Path/To/YourAssembly.dll", 38 | Output = "Mappers" 39 | }) 40 | }; 41 | } 42 | } -------------------------------------------------------------------------------- /src/Mapster.Tool/Mapster.Tool.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net7.0;net6.0 6 | true 7 | true 8 | dotnet-mapster 9 | Tool to generate object mapping using Mapster 10 | Mapster;Tool 11 | true 12 | Mapster.Tool.snk 13 | 8.4.0-pre06 14 | enable 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/Mapster.Tool/Mapster.Tool.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.Tool/Mapster.Tool.snk -------------------------------------------------------------------------------- /src/Mapster.Tool/ModelOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using CommandLine; 3 | using CommandLine.Text; 4 | 5 | namespace Mapster.Tool 6 | { 7 | [Verb("model", HelpText = "Generate models")] 8 | public class ModelOptions 9 | { 10 | [Option('a', "assembly", Required = true, HelpText = "Assembly to scan")] 11 | public string Assembly { get; set; } 12 | 13 | [Option('o', "output", Required = false, Default = "Models", HelpText = "Output directory.")] 14 | public string Output { get; set; } 15 | 16 | [Option('n', "namespace", Required = false, HelpText = "Namespace for models")] 17 | public string? Namespace { get; set; } 18 | 19 | [Option('p', "printFullTypeName", Required = false, HelpText = "Set true to print full type name")] 20 | public bool PrintFullTypeName { get; set; } 21 | 22 | [Option('r', "isRecordType", Required = false, HelpText = "Generate record type")] 23 | public bool IsRecordType { get; set; } 24 | 25 | [Option('b', "baseNamespace", Required = false, HelpText = "Provide base namespace to generate nested output & namespace")] 26 | public string? BaseNamespace { get; set; } 27 | 28 | [Option('s', "skipExisting", Required = false, HelpText = "Set true to skip generating already existing files")] 29 | public bool SkipExistingFiles { get; set; } 30 | 31 | [Option('N', "nullableDirective", Required = false, HelpText = "Set true to add \"#nullable enable\" to the top of generated model files")] 32 | public bool GenerateNullableDirective { get; set; } 33 | 34 | [Usage(ApplicationAlias = "dotnet mapster model")] 35 | public static IEnumerable Examples => 36 | new List 37 | { 38 | new Example("Generate models", new MapperOptions 39 | { 40 | Assembly = "/Path/To/YourAssembly.dll", 41 | Output = "Models" 42 | }) 43 | }; 44 | } 45 | } -------------------------------------------------------------------------------- /src/Mapster.Tool/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:49597/", 7 | "sslPort": 44315 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "Mapster.Tool": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "https://localhost:5001;http://localhost:5000" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Mapster.Tool/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster.Tool/icon.png -------------------------------------------------------------------------------- /src/Mapster/Adapters/BaseAfterMapper.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | namespace Mapster.Adapters 4 | { 5 | public abstract class BaseAfterMapper 6 | { 7 | protected virtual int Score => 0; 8 | 9 | public virtual int? Priority(PreCompileArgument arg) 10 | { 11 | return CanMap(arg) ? Score : (int?)null; 12 | } 13 | 14 | protected abstract bool CanMap(PreCompileArgument arg); 15 | 16 | public LambdaExpression CreateAfterMapFunc(CompileArgument arg) 17 | { 18 | var p = Expression.Parameter(arg.SourceType); 19 | var p2 = Expression.Parameter(arg.DestinationType); 20 | var body = CreateExpressionBody(p, p2, arg); 21 | return Expression.Lambda(body, p, p2); 22 | } 23 | 24 | protected abstract Expression CreateExpressionBody(Expression source, Expression destination, CompileArgument arg); 25 | 26 | public TypeAdapterRule CreateRule() 27 | { 28 | var settings = new TypeAdapterSettings(); 29 | settings.AfterMappingFactories.Add(CreateAfterMapFunc); 30 | var rule = new TypeAdapterRule 31 | { 32 | Priority = Priority, 33 | Settings = settings, 34 | }; 35 | DecorateRule(rule); 36 | return rule; 37 | } 38 | 39 | protected virtual void DecorateRule(TypeAdapterRule rule) { } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Mapster/Adapters/DelegateAdapter.cs: -------------------------------------------------------------------------------- 1 | using Mapster.Utils; 2 | using System; 3 | using System.Linq.Expressions; 4 | 5 | namespace Mapster.Adapters 6 | { 7 | internal class DelegateAdapter : BaseAdapter 8 | { 9 | readonly LambdaExpression _lambda; 10 | public DelegateAdapter(LambdaExpression lambda) 11 | { 12 | _lambda = lambda; 13 | } 14 | 15 | protected override bool CanMap(PreCompileArgument arg) 16 | { 17 | throw new NotImplementedException(); 18 | } 19 | 20 | protected override Expression CreateInstantiationExpression(Expression source, Expression? destination, CompileArgument arg) 21 | { 22 | if (destination == null) 23 | return _lambda.Apply(arg.MapType, source); 24 | else 25 | return _lambda.Apply(arg.MapType, source, destination); 26 | } 27 | 28 | protected override Expression CreateBlockExpression(Expression source, Expression destination, CompileArgument arg) 29 | { 30 | return Expression.Empty(); 31 | } 32 | 33 | protected override Expression CreateInlineExpression(Expression source, CompileArgument arg) 34 | { 35 | return CreateInstantiationExpression(source, arg); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Mapster/Adapters/ObjectAdapter.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | namespace Mapster.Adapters 4 | { 5 | internal class ObjectAdapter : BaseAdapter 6 | { 7 | protected override int Score => -111; //must do before all class adapters 8 | 9 | protected override bool CanMap(PreCompileArgument arg) 10 | { 11 | return arg.SourceType == typeof(object) || arg.DestinationType == typeof(object); 12 | } 13 | 14 | protected override Expression CreateInstantiationExpression(Expression source, Expression? destination, CompileArgument arg) 15 | { 16 | var srcType = arg.SourceType; 17 | var destType = arg.DestinationType; 18 | if (srcType == destType) 19 | return source; 20 | if (destType == typeof(object)) 21 | return Expression.Convert(source, destType); 22 | return arg.Context.Config.CreateDynamicMapInvokeExpressionBody(arg.DestinationType, source); 23 | } 24 | 25 | protected override Expression CreateBlockExpression(Expression source, Expression destination, CompileArgument arg) 26 | { 27 | return Expression.Empty(); 28 | } 29 | 30 | protected override Expression CreateInlineExpression(Expression source, CompileArgument arg) 31 | { 32 | return CreateInstantiationExpression(source, arg); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Mapster/Adapters/ObjectType.cs: -------------------------------------------------------------------------------- 1 | namespace Mapster.Adapters 2 | { 3 | public enum ObjectType 4 | { 5 | Primitive, 6 | Collection, 7 | Class, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Mapster/Adapters/RecordTypeAdapter.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using System.Reflection; 3 | using Mapster.Utils; 4 | 5 | namespace Mapster.Adapters 6 | { 7 | internal class RecordTypeAdapter : BaseClassAdapter 8 | { 9 | protected override int Score => -149; 10 | protected override bool UseTargetValue => false; 11 | 12 | protected override bool CanMap(PreCompileArgument arg) 13 | { 14 | return arg.DestinationType.IsRecordType(); 15 | } 16 | 17 | protected override Expression CreateInstantiationExpression(Expression source, Expression? destination, CompileArgument arg) 18 | { 19 | //new TDestination(src.Prop1, src.Prop2) 20 | 21 | if (arg.GetConstructUsing() != null) 22 | return base.CreateInstantiationExpression(source, destination, arg); 23 | 24 | var destType = arg.DestinationType.GetTypeInfo().IsInterface 25 | ? DynamicTypeGenerator.GetTypeForInterface(arg.DestinationType, arg.Settings.Includes.Count > 0) 26 | : arg.DestinationType; 27 | if (destType == null) 28 | return base.CreateInstantiationExpression(source, destination, arg); 29 | var ctor = destType.GetConstructors()[0]; 30 | var classModel = GetConstructorModel(ctor, false); 31 | var classConverter = CreateClassConverter(source, classModel, arg); 32 | return CreateInstantiationExpression(source, classConverter, arg); 33 | } 34 | 35 | protected override Expression CreateBlockExpression(Expression source, Expression destination, CompileArgument arg) 36 | { 37 | return Expression.Empty(); 38 | } 39 | 40 | protected override Expression CreateInlineExpression(Expression source, CompileArgument arg) 41 | { 42 | return CreateInstantiationExpression(source, arg); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/Mapster/Adapters/StringAdapter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | // ReSharper disable once RedundantUsingDirective 5 | using System.Reflection; 6 | 7 | namespace Mapster.Adapters 8 | { 9 | internal class StringAdapter : PrimitiveAdapter 10 | { 11 | protected override int Score => -110; //must do before all class adapters 12 | 13 | protected override bool CanMap(PreCompileArgument arg) 14 | { 15 | return arg.SourceType == typeof(string) || arg.DestinationType == typeof(string); 16 | } 17 | 18 | protected override Expression ConvertType(Expression source, Type destinationType, CompileArgument arg) 19 | { 20 | if (destinationType == typeof(string)) 21 | { 22 | var method = source.Type.GetMethod("ToString", Type.EmptyTypes) 23 | ?? typeof(object).GetMethod("ToString", Type.EmptyTypes); 24 | return Expression.Call(source, method!); 25 | } 26 | else //if (sourceType == typeof(string)) 27 | { 28 | var method = destinationType.GetMethod("Parse", new[] { typeof(string) }); 29 | if (method != null) 30 | return Expression.Call(method, source); 31 | } 32 | 33 | return base.ConvertType(source, destinationType, arg); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Mapster/Compile/CompileArgument.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using Mapster.Utils; 6 | 7 | namespace Mapster 8 | { 9 | public class CompileArgument 10 | { 11 | public Type SourceType { get; set; } 12 | public Type DestinationType { get; set; } 13 | public MapType MapType { get; set; } 14 | public bool ExplicitMapping { get; set; } 15 | public TypeAdapterSettings Settings { get; set; } 16 | public CompileContext Context { get; set; } 17 | public bool UseDestinationValue { get; set; } 18 | 19 | private HashSet? _srcNames; 20 | internal HashSet GetSourceNames() 21 | { 22 | return _srcNames ??= (from it in Settings.Resolvers 23 | where it.SourceMemberName != null 24 | select it.SourceMemberName!.Split('.').First()).ToHashSet(); 25 | } 26 | 27 | private HashSet? _destNames; 28 | internal HashSet GetDestinationNames() 29 | { 30 | return _destNames ??= (from it in Settings.Resolvers 31 | where it.DestinationMemberName != null 32 | select it.DestinationMemberName.Split('.').First()).ToHashSet(); 33 | } 34 | 35 | private bool _fetchConstructUsing; 36 | private LambdaExpression? _constructUsing; 37 | internal LambdaExpression? GetConstructUsing() 38 | { 39 | if (_fetchConstructUsing) return _constructUsing; 40 | _constructUsing = Settings.ConstructUsingFactory?.Invoke(this); 41 | _fetchConstructUsing = true; 42 | return _constructUsing; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/Mapster/Compile/CompileContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq.Expressions; 3 | using Mapster.Models; 4 | 5 | namespace Mapster 6 | { 7 | public class CompileContext 8 | { 9 | public HashSet Running { get; } = new(); 10 | public Stack Configs { get; } = new(); 11 | public TypeAdapterConfig Config => Configs.Peek(); 12 | public int? MaxDepth { get; set; } 13 | public int Depth { get; set; } 14 | public HashSet ExtraParameters { get; } = new(); 15 | 16 | internal bool IsSubFunction() 17 | { 18 | return MaxDepth.HasValue || ExtraParameters.Count > 0; 19 | } 20 | 21 | public CompileContext(TypeAdapterConfig config) 22 | { 23 | Configs.Push(config); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/Mapster/Compile/CompileException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | 4 | namespace Mapster 5 | { 6 | public class CompileException : InvalidOperationException 7 | { 8 | public CompileException(CompileArgument argument, Exception innerException) : base(null, innerException) 9 | { 10 | Argument = argument; 11 | } 12 | 13 | public override string Message => 14 | "Error while compiling\n" + 15 | $"source={Argument.SourceType}\n" + 16 | $"destination={Argument.DestinationType}\n" + 17 | $"type={Argument.MapType}"; 18 | 19 | public CompileArgument Argument { get; } 20 | public LambdaExpression? Expression { get; internal set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Mapster/Compile/PreCompileArgument.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mapster 4 | { 5 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "")] 6 | public class PreCompileArgument 7 | { 8 | public Type SourceType; 9 | public Type DestinationType; 10 | public MapType MapType; 11 | public bool ExplicitMapping; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Mapster/Enums/AccessModifier.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mapster 4 | { 5 | [Flags] 6 | public enum AccessModifier 7 | { 8 | None = 0, 9 | Private = 1, 10 | Protected = 2, 11 | Internal = 4, 12 | ProtectedInternal = 6, 13 | NonPublic = 7, 14 | Public = 8, 15 | } 16 | } -------------------------------------------------------------------------------- /src/Mapster/Enums/EnumMappingStrategy.cs: -------------------------------------------------------------------------------- 1 | namespace Mapster 2 | { 3 | public enum EnumMappingStrategy 4 | { 5 | ByValue, 6 | ByName, 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Mapster/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | using Mapster.Models; 5 | 6 | namespace Mapster 7 | { 8 | public static class Extensions 9 | { 10 | public static IQueryable ProjectToType(this IQueryable source, TypeAdapterConfig? config = null) 11 | { 12 | config ??= TypeAdapterConfig.GlobalSettings; 13 | var mockCall = config.GetProjectionCallExpression(source.ElementType, typeof(TDestination)); 14 | var sourceCall = Expression.Call(mockCall.Method, source.Expression, mockCall.Arguments[1]); 15 | return source.Provider.CreateQuery(sourceCall); 16 | } 17 | 18 | public static IQueryable ProjectToType(this IQueryable source, Type destinationType, TypeAdapterConfig? config = null) 19 | { 20 | config ??= TypeAdapterConfig.GlobalSettings; 21 | var mockCall = config.GetProjectionCallExpression(source.ElementType, destinationType); 22 | var sourceCall = Expression.Call(mockCall.Method, source.Expression, mockCall.Arguments[1]); 23 | return source.Provider.CreateQuery(sourceCall); 24 | } 25 | 26 | public static bool HasCustomAttribute(this IMemberModel member, Type type) 27 | { 28 | return member.GetCustomAttributesData().Any(attr => attr.GetAttributeType() == type); 29 | } 30 | 31 | public static bool HasCustomAttribute(this IMemberModel member) where T : Attribute 32 | { 33 | return member.GetCustomAttributesData().Any(attr => attr.GetAttributeType() == typeof(T)); 34 | } 35 | 36 | public static T? GetCustomAttribute(this IMemberModel member) where T : Attribute 37 | { 38 | return (T?) member.GetCustomAttributes(true).FirstOrDefault(attr => attr is T); 39 | } 40 | 41 | internal static T? GetCustomAttributeFromData(this IMemberModel member) where T : Attribute 42 | { 43 | var attr = member.GetCustomAttributesData().FirstOrDefault(it => it.GetAttributeType() == typeof(T)); 44 | return attr?.CreateCustomAttribute(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Mapster/Interfaces/IAdapterBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Mapster 4 | { 5 | public interface IAdapterBuilder 6 | { 7 | TypeAdapterConfig Config { get; } 8 | bool HasParameter { get; } 9 | Dictionary Parameters { get; } 10 | MapContextScope CreateMapContextScope(); 11 | TDestination AdaptToType(); 12 | TDestination AdaptTo(TDestination destination); 13 | } 14 | 15 | public interface IAdapterBuilder : IAdapterBuilder 16 | { 17 | T Source { get; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Mapster/Interfaces/IApplyable.cs: -------------------------------------------------------------------------------- 1 | namespace Mapster 2 | { 3 | public interface IApplyable 4 | { 5 | void Apply(object other); 6 | } 7 | public interface IApplyable : IApplyable 8 | { 9 | void Apply(T other); 10 | } 11 | } -------------------------------------------------------------------------------- /src/Mapster/Interfaces/IMapFrom.cs: -------------------------------------------------------------------------------- 1 | namespace Mapster; 2 | 3 | public interface IMapFrom 4 | { 5 | public void ConfigureMapping(TypeAdapterConfig config) 6 | { 7 | config.NewConfig(typeof(TSource), GetType()); 8 | } 9 | } -------------------------------------------------------------------------------- /src/Mapster/Interfaces/IRegister.cs: -------------------------------------------------------------------------------- 1 | namespace Mapster 2 | { 3 | /// 4 | /// Implement to allow mappings to be found when scanning assemblies. 5 | /// Place mappings in the Register method. 6 | /// Call TypeAdapterConfig.ScanAssemblies to perform scanning 7 | /// 8 | public interface IRegister 9 | { 10 | void Register(TypeAdapterConfig config); 11 | } 12 | } -------------------------------------------------------------------------------- /src/Mapster/Interfaces/ITypeAdapterBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Linq.Expressions; 4 | using System.Runtime.CompilerServices; 5 | 6 | namespace Mapster 7 | { 8 | public interface ITypeAdapterBuilder : IAdapterBuilder 9 | { 10 | [SuppressMessage("ReSharper", "ExplicitCallerInfoArgument")] 11 | ITypeAdapterBuilder ForkConfig(Action action, 12 | #if !NET40 13 | [CallerFilePath] 14 | #endif 15 | string key1 = "", 16 | #if !NET40 17 | [CallerLineNumber] 18 | #endif 19 | int key2 = 0); 20 | ITypeAdapterBuilder AddParameters(string name, object value); 21 | Expression> CreateMapExpression(); 22 | Expression> CreateMapToTargetExpression(); 23 | Expression> CreateProjectionExpression(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Mapster/Mapster.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | A fast, fun and stimulating object to object mapper. Kind of like AutoMapper, just simpler and way, way faster. 5 | Copyright (c) 2016 Chaowlert Chaisrichalermpol, Eric Swann 6 | chaowlert;eric_swann 7 | net7.0;net6.0 8 | Mapster 9 | A fast, fun and stimulating object to object mapper. Kind of like AutoMapper, just simpler and way, way faster. 10 | Mapster 11 | Mapper;AutoMapper;Fast;Mapping 12 | icon.png 13 | https://cloud.githubusercontent.com/assets/5763993/26522718/d16f3e42-4330-11e7-9b78-f8c7402624e7.png 14 | https://github.com/MapsterMapper/Mapster 15 | https://github.com/MapsterMapper/Mapster 16 | 17 | true 18 | Mapster 19 | 7.4.0-pre06 20 | enable 21 | 1701;1702;8618 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/Mapster/Mapster.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | True 5 | True 6 | True 7 | True -------------------------------------------------------------------------------- /src/Mapster/Mapster.nuget.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/Mapster/Mapster.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster/Mapster.snk -------------------------------------------------------------------------------- /src/Mapster/Models/ClassMapping.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Reflection; 3 | 4 | namespace Mapster.Models 5 | { 6 | internal class ClassMapping 7 | { 8 | public ConstructorInfo? ConstructorInfo { get; set; } 9 | public List Members { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Mapster/Models/ClassModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Reflection; 3 | 4 | namespace Mapster.Models 5 | { 6 | internal class ClassModel 7 | { 8 | public bool BreakOnUnmatched { get; set; } 9 | public ConstructorInfo? ConstructorInfo { get; set; } 10 | public IEnumerable Members { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Mapster/Models/FieldModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Reflection; 5 | 6 | namespace Mapster.Models 7 | { 8 | public class FieldModel : IMemberModelEx 9 | { 10 | private readonly FieldInfo _fieldInfo; 11 | public FieldModel(FieldInfo fieldInfo) 12 | { 13 | _fieldInfo = fieldInfo; 14 | } 15 | 16 | public Type Type => _fieldInfo.FieldType; 17 | public string Name => _fieldInfo.Name; 18 | public object Info => _fieldInfo; 19 | public AccessModifier SetterModifier => _fieldInfo.IsInitOnly ? AccessModifier.None : _fieldInfo.GetAccessModifier(); 20 | public AccessModifier AccessModifier => _fieldInfo.GetAccessModifier(); 21 | 22 | public Expression GetExpression(Expression source) 23 | { 24 | return Expression.Field(source, _fieldInfo); 25 | } 26 | public Expression SetExpression(Expression source, Expression value) 27 | { 28 | return Expression.Assign(GetExpression(source), value); 29 | } 30 | public IEnumerable GetCustomAttributes(bool inherit) 31 | { 32 | return _fieldInfo.GetCustomAttributes(inherit); 33 | } 34 | public IEnumerable GetCustomAttributesData() 35 | { 36 | return _fieldInfo.GetCustomAttributesData(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Mapster/Models/IMemberModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | 5 | namespace Mapster.Models 6 | { 7 | public interface IMemberModel 8 | { 9 | Type Type { get; } 10 | string Name { get; } 11 | object? Info { get; } 12 | AccessModifier SetterModifier { get; } 13 | AccessModifier AccessModifier { get; } 14 | 15 | IEnumerable GetCustomAttributes(bool inherit); 16 | IEnumerable GetCustomAttributesData(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Mapster/Models/IMemberModelEx.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | namespace Mapster.Models 4 | { 5 | internal interface IMemberModelEx: IMemberModel 6 | { 7 | Expression GetExpression(Expression source); 8 | Expression SetExpression(Expression source, Expression value); 9 | } 10 | } -------------------------------------------------------------------------------- /src/Mapster/Models/InvokerModel.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using Mapster.Utils; 3 | 4 | namespace Mapster.Models 5 | { 6 | public class InvokerModel 7 | { 8 | public string DestinationMemberName { get; set; } 9 | public LambdaExpression? Invoker { get; set; } 10 | public string? SourceMemberName { get; set; } 11 | public LambdaExpression? Condition { get; set; } 12 | public bool IsChildPath { get; set; } 13 | 14 | public InvokerModel? Next(ParameterExpression source, string destMemberName) 15 | { 16 | if (!DestinationMemberName.StartsWith(destMemberName + ".")) 17 | return null; 18 | 19 | return new InvokerModel 20 | { 21 | DestinationMemberName = DestinationMemberName.Substring(destMemberName.Length + 1), 22 | Condition = IsChildPath || Condition == null 23 | ? Condition 24 | : Expression.Lambda(Condition.Apply(source), source), 25 | Invoker = IsChildPath 26 | ? Invoker 27 | : Expression.Lambda(GetInvokingExpression(source), source), 28 | SourceMemberName = SourceMemberName, 29 | IsChildPath = true, 30 | }; 31 | } 32 | 33 | public Expression GetInvokingExpression(Expression exp, MapType mapType = MapType.Map) 34 | { 35 | if (IsChildPath) 36 | return Invoker!.Body; 37 | return SourceMemberName != null 38 | ? ExpressionEx.PropertyOrFieldPath(exp, SourceMemberName) 39 | : Invoker!.Apply(mapType, exp); 40 | } 41 | 42 | public Expression? GetConditionExpression(Expression exp, MapType mapType = MapType.Map) 43 | { 44 | return IsChildPath 45 | ? Condition?.Body 46 | : Condition?.Apply(mapType, exp); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/Mapster/Models/KeyValuePairModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | using System.Reflection; 6 | 7 | namespace Mapster.Models 8 | { 9 | public class KeyValuePairModel : IMemberModelEx 10 | { 11 | readonly Func _getFn; 12 | readonly Func _setFn; 13 | public KeyValuePairModel(string name, Type type, 14 | Func getFn, 15 | Func setFn) 16 | { 17 | Name = name; 18 | Type = type; 19 | _getFn = getFn; 20 | _setFn = setFn; 21 | } 22 | 23 | public Type Type { get; } 24 | 25 | public string Name { get; } 26 | 27 | public object? Info => null; 28 | 29 | public AccessModifier SetterModifier => AccessModifier.Public; 30 | 31 | public AccessModifier AccessModifier => AccessModifier.Public; 32 | 33 | public IEnumerable GetCustomAttributes(bool inherit) => Enumerable.Empty(); 34 | 35 | public IEnumerable GetCustomAttributesData() => 36 | Enumerable.Empty(); 37 | 38 | public Expression GetExpression(Expression source) 39 | { 40 | return _getFn(source, Expression.Constant(Name)); 41 | } 42 | public Expression SetExpression(Expression source, Expression value) 43 | { 44 | return _setFn(source, Expression.Constant(Name), value); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Mapster/Models/MemberMapping.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq.Expressions; 3 | 4 | namespace Mapster.Models 5 | { 6 | internal class MemberMapping 7 | { 8 | public Expression Getter; 9 | public IMemberModelEx DestinationMember; 10 | public IgnoreDictionary.IgnoreItem Ignore; 11 | public List NextResolvers; 12 | public IgnoreDictionary NextIgnore; 13 | public ParameterExpression Source; 14 | public ParameterExpression? Destination; 15 | public bool UseDestinationValue; 16 | 17 | public bool HasSettings() 18 | { 19 | return NextResolvers.Count > 0 || NextIgnore.Count > 0; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Mapster/Models/ParameterModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Reflection; 5 | using Mapster.Utils; 6 | 7 | namespace Mapster.Models 8 | { 9 | public class ParameterModel : IMemberModelEx 10 | { 11 | private readonly ParameterInfo _parameterInfo; 12 | public ParameterModel(ParameterInfo parameterInfo) 13 | { 14 | _parameterInfo = parameterInfo; 15 | } 16 | 17 | public Type Type => _parameterInfo.ParameterType; 18 | public string Name => _parameterInfo.Name.ToPascalCase(); 19 | public object Info => _parameterInfo; 20 | public AccessModifier SetterModifier => AccessModifier.Public; 21 | public AccessModifier AccessModifier => AccessModifier.Public; 22 | 23 | public Expression GetExpression(Expression source) 24 | { 25 | return Expression.Variable(Type, _parameterInfo.Name); 26 | } 27 | public Expression SetExpression(Expression source, Expression value) 28 | { 29 | return Expression.Assign(GetExpression(source), value); 30 | } 31 | public IEnumerable GetCustomAttributes(bool inherit) 32 | { 33 | return _parameterInfo.GetCustomAttributes(inherit); 34 | } 35 | public IEnumerable GetCustomAttributesData() 36 | { 37 | return _parameterInfo.GetCustomAttributesData(); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Mapster/Models/PropertyModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq.Expressions; 4 | using System.Reflection; 5 | 6 | namespace Mapster.Models 7 | { 8 | public class PropertyModel : IMemberModelEx 9 | { 10 | private readonly PropertyInfo _propertyInfo; 11 | public PropertyModel(PropertyInfo propertyInfo) 12 | { 13 | _propertyInfo = propertyInfo; 14 | } 15 | 16 | public Type Type => _propertyInfo.PropertyType; 17 | public virtual string Name => _propertyInfo.Name; 18 | public object Info => _propertyInfo; 19 | 20 | public AccessModifier SetterModifier 21 | { 22 | get 23 | { 24 | var setter = _propertyInfo.GetSetMethod(true); 25 | return setter?.GetAccessModifier() ?? AccessModifier.None; 26 | } 27 | } 28 | public AccessModifier AccessModifier 29 | { 30 | get 31 | { 32 | var getter = _propertyInfo.GetGetMethod(true); 33 | return getter?.GetAccessModifier() ?? AccessModifier.None; 34 | } 35 | } 36 | 37 | public virtual Expression GetExpression(Expression source) 38 | { 39 | return Expression.Property(source, _propertyInfo); 40 | } 41 | public Expression SetExpression(Expression source, Expression value) 42 | { 43 | return Expression.Assign(GetExpression(source), value); 44 | } 45 | public IEnumerable GetCustomAttributes(bool inherit) 46 | { 47 | return _propertyInfo.GetCustomAttributes(inherit); 48 | } 49 | public IEnumerable GetCustomAttributesData() 50 | { 51 | return _propertyInfo.GetCustomAttributesData(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Mapster/Models/TypeTuple.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mapster.Models 4 | { 5 | public readonly struct TypeTuple : IEquatable 6 | { 7 | public bool Equals(TypeTuple other) 8 | { 9 | return Source == other.Source && Destination == other.Destination; 10 | } 11 | 12 | public override bool Equals(object obj) 13 | { 14 | if (!(obj is TypeTuple)) 15 | return false; 16 | return Equals((TypeTuple)obj); 17 | } 18 | 19 | public override int GetHashCode() 20 | { 21 | return (Source.GetHashCode() << 16) ^ (Destination.GetHashCode() & 65535); 22 | } 23 | 24 | public static bool operator ==(TypeTuple left, TypeTuple right) 25 | { 26 | return left.Equals(right); 27 | } 28 | 29 | public static bool operator !=(TypeTuple left, TypeTuple right) 30 | { 31 | return !left.Equals(right); 32 | } 33 | 34 | public Type Source { get; } 35 | public Type Destination { get; } 36 | 37 | public TypeTuple(Type source, Type destination) 38 | { 39 | Source = source; 40 | Destination = destination; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Mapster/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using Mapster; 5 | 6 | // General Information about an assembly is controlled through the following 7 | // set of attributes. Change these attribute values to modify the information 8 | // associated with an assembly. 9 | [assembly: AssemblyTrademark("")] 10 | [assembly: AssemblyCulture("")] 11 | 12 | // Setting ComVisible to false makes the types in this assembly not visible 13 | // to COM components. If you need to access a type in this assembly from 14 | // COM, set the ComVisible attribute to true on that type. 15 | [assembly: ComVisible(false)] 16 | 17 | // The following GUID is for the ID of the typelib if this project is exposed to COM 18 | [assembly: Guid("df5bd29d-85e6-4621-b3cb-1561e98f9697")] 19 | 20 | // Version information for an assembly consists of the following four values: 21 | // 22 | // Major Version 23 | // Minor Version 24 | // Build Number 25 | // Revision 26 | // 27 | // You can specify all the values or you can default the Build and Revision Numbers 28 | // by using the '*' as shown below: 29 | // [assembly: AssemblyVersion("1.0.*")] 30 | [assembly: InternalsVisibleTo("Mapster.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001000936c652e8d888894759aa92c40f62c30d691cb153214c6ddff550ee7b68b320eefeed3fceef9a7cea5cfce035983b4d6c22ea7a925e375116cdf8f6ea6259ebe263fbd9a1332037e5f7da63df86124223c81667c86b387372aa769a145ddadb378ba6dfe2b4f4266c89eb54b477938ba265321fa77f953f2abaacfed62e66bd")] 31 | 32 | [assembly: TypeForwardedTo(typeof(MapContext))] 33 | [assembly: TypeForwardedTo(typeof(MapContextScope))] 34 | [assembly: TypeForwardedTo(typeof(MapType))] 35 | [assembly: TypeForwardedTo(typeof(MemberSide))] 36 | -------------------------------------------------------------------------------- /src/Mapster/Settings/GetMemberName.cs: -------------------------------------------------------------------------------- 1 | using Mapster.Models; 2 | using System; 3 | 4 | namespace Mapster 5 | { 6 | public static class GetMemberName 7 | { 8 | public static readonly Func AdaptMember = (model, side) => 9 | { 10 | var memberAttr = model.GetCustomAttributeFromData(); 11 | if (memberAttr == null) 12 | return null; 13 | return memberAttr.Side == null || memberAttr.Side == side ? memberAttr.Name : null; 14 | }; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Mapster/Settings/ShouldMapMember.cs: -------------------------------------------------------------------------------- 1 | using Mapster.Models; 2 | using System; 3 | using System.Reflection; 4 | using System.Runtime.CompilerServices; 5 | 6 | namespace Mapster 7 | { 8 | public static class ShouldMapMember 9 | { 10 | public static readonly Func AllowNonPublic = (model, _) => 11 | (model.AccessModifier & AccessModifier.NonPublic) == 0 12 | ? (bool?) null 13 | : !(model.Info is FieldInfo) || !model.HasCustomAttribute(); 14 | public static readonly Func AllowPublic = (model, _) => model.AccessModifier == AccessModifier.Public ? (bool?)true : null; 15 | public static readonly Func IgnoreAdaptIgnore = (model, side) => 16 | { 17 | var ignoreAttr = model.GetCustomAttributeFromData(); 18 | if (ignoreAttr == null) 19 | return null; 20 | return ignoreAttr.Side == null || ignoreAttr.Side == side ? (bool?) false : null; 21 | }; 22 | public static readonly Func AllowAdaptMember = (model, side) => 23 | { 24 | var memberAttr = model.GetCustomAttributeFromData(); 25 | if (memberAttr == null) 26 | return null; 27 | return memberAttr.Side == null || memberAttr.Side == side ? (bool?) true : null; 28 | }; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Mapster/Settings/UseDestinationValue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Mapster.Models; 3 | 4 | namespace Mapster 5 | { 6 | public static class UseDestinationValue 7 | { 8 | public static readonly Func Attribute = model => model.HasCustomAttribute(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Mapster/TypeAdapterRule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Mapster 4 | { 5 | public class TypeAdapterRule 6 | { 7 | public Func Priority { get; set; } 8 | public TypeAdapterSettings Settings { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/Mapster/Utils/BlockExpressionDetector.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | namespace Mapster.Utils 4 | { 5 | sealed class BlockExpressionDetector : ExpressionVisitor 6 | { 7 | public bool IsBlockExpression { get; private set; } 8 | 9 | public override Expression? Visit(Expression? node) 10 | { 11 | if (IsBlockExpression || node == null) 12 | return node; 13 | 14 | switch (node.NodeType) 15 | { 16 | case ExpressionType.Assign: 17 | case ExpressionType.Block: 18 | case ExpressionType.DebugInfo: 19 | case ExpressionType.Goto: 20 | case ExpressionType.Label: 21 | case ExpressionType.Loop: 22 | case ExpressionType.Switch: 23 | case ExpressionType.Throw: 24 | case ExpressionType.Try: 25 | case ExpressionType.AddAssign: 26 | case ExpressionType.AndAssign: 27 | case ExpressionType.DivideAssign: 28 | case ExpressionType.ExclusiveOrAssign: 29 | case ExpressionType.LeftShiftAssign: 30 | case ExpressionType.ModuloAssign: 31 | case ExpressionType.MultiplyAssign: 32 | case ExpressionType.OrAssign: 33 | case ExpressionType.PowerAssign: 34 | case ExpressionType.RightShiftAssign: 35 | case ExpressionType.SubtractAssign: 36 | case ExpressionType.AddAssignChecked: 37 | case ExpressionType.MultiplyAssignChecked: 38 | case ExpressionType.SubtractAssignChecked: 39 | case ExpressionType.PreIncrementAssign: 40 | case ExpressionType.PreDecrementAssign: 41 | case ExpressionType.PostIncrementAssign: 42 | case ExpressionType.PostDecrementAssign: 43 | IsBlockExpression = true; 44 | return node; 45 | } 46 | 47 | return base.Visit(node); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Mapster/Utils/ComplexExpressionVisitor.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | namespace Mapster.Utils 4 | { 5 | sealed class ComplexExpressionVisitor : ExpressionVisitor 6 | { 7 | public bool IsComplex { get; private set; } 8 | public override Expression? Visit(Expression? node) 9 | { 10 | if (node == null) 11 | return null; 12 | switch (node.NodeType) 13 | { 14 | case ExpressionType.ArrayIndex: 15 | case ExpressionType.ArrayLength: 16 | case ExpressionType.Call: 17 | case ExpressionType.Constant: 18 | case ExpressionType.Convert: 19 | case ExpressionType.ConvertChecked: 20 | case ExpressionType.Default: 21 | case ExpressionType.Index: 22 | case ExpressionType.IsFalse: 23 | case ExpressionType.IsTrue: 24 | case ExpressionType.MemberAccess: 25 | case ExpressionType.Negate: 26 | case ExpressionType.NegateChecked: 27 | case ExpressionType.Not: 28 | case ExpressionType.OnesComplement: 29 | case ExpressionType.Parameter: 30 | case ExpressionType.UnaryPlus: 31 | case ExpressionType.Unbox: 32 | return base.Visit(node); 33 | default: 34 | IsComplex = true; 35 | return node; 36 | } 37 | } 38 | 39 | protected override Expression VisitMethodCall(MethodCallExpression node) 40 | { 41 | if (!node.Method.IsSpecialName || !node.Method.Name.StartsWith("get_")) 42 | IsComplex = true; 43 | return node; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Mapster/Utils/CoreExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Mapster.Utils 4 | { 5 | internal static class CoreExtensions 6 | { 7 | public static string ToPascalCase(this string name) 8 | { 9 | return MapsterHelper.PascalCase(name); 10 | } 11 | 12 | public static void LockAdd(this List list, T item) 13 | { 14 | lock (list) 15 | { 16 | list.Add(item); 17 | } 18 | } 19 | 20 | public static void LockRemove(this List list, T item) 21 | { 22 | lock (list) 23 | { 24 | list.Remove(item); 25 | } 26 | } 27 | 28 | #if !NET6_0_OR_GREATER 29 | public static HashSet ToHashSet(this IEnumerable source) 30 | { 31 | return new HashSet(source); 32 | } 33 | #endif 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Mapster/Utils/InterfaceDynamicMapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | 6 | namespace Mapster.Utils; 7 | 8 | public class InterfaceDynamicMapper 9 | { 10 | private readonly TypeAdapterConfig _config; 11 | private readonly List _types; 12 | 13 | public InterfaceDynamicMapper(TypeAdapterConfig config, List types) 14 | { 15 | _config = config; 16 | _types = types; 17 | } 18 | 19 | internal void ApplyMappingFromAssembly() 20 | { 21 | foreach (var type in _types) 22 | { 23 | var instance = Activator.CreateInstance(type); 24 | var method = GetMethod(type); 25 | method!.Invoke(instance, new object[] { _config }); 26 | } 27 | } 28 | 29 | private static MethodInfo GetMethod(Type type) 30 | { 31 | const string methodName = "ConfigureMapping"; 32 | var method = type.GetMethod(methodName); 33 | if (method == null) return type.GetInterface("IMapFrom`1")!.GetMethod(methodName)!; 34 | var parameters = method.GetParameters(); 35 | var condition = parameters.Length == 1 && parameters[0].ParameterType == typeof(TypeAdapterConfig); 36 | if (!condition) 37 | { 38 | throw new Exception($"{methodName} is not implemented right or it's ambiguous!"); 39 | } 40 | 41 | return method; 42 | } 43 | } -------------------------------------------------------------------------------- /src/Mapster/Utils/ParameterExpressionReplacer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | using System.Linq.Expressions; 3 | 4 | namespace Mapster.Utils 5 | { 6 | sealed class ParameterExpressionReplacer : ExpressionVisitor 7 | { 8 | //fields 9 | readonly ReadOnlyCollection _from; 10 | readonly Expression[] _to; 11 | 12 | public int[] ReplaceCounts { get; } 13 | 14 | //constructors 15 | public ParameterExpressionReplacer(ReadOnlyCollection from, params Expression[] to) 16 | { 17 | _from = from; 18 | _to = to; 19 | ReplaceCounts = new int[_to.Length]; 20 | } 21 | 22 | protected override Expression VisitParameter(ParameterExpression node) 23 | { 24 | for (var i = 0; i < _from.Count; i++) 25 | { 26 | if (node != _from[i]) 27 | continue; 28 | if (i >= _to.Length) 29 | return node.Type.CreateDefault(); 30 | 31 | ReplaceCounts[i]++; 32 | return _to[i].To(node.Type, true); 33 | } 34 | return node; 35 | } 36 | 37 | protected override Expression VisitConditional(ConditionalExpression node) 38 | { 39 | var cond = (ConditionalExpression)base.VisitConditional(node); 40 | if (cond.Test.NodeType != ExpressionType.Equal && cond.Test.NodeType != ExpressionType.NotEqual) 41 | return cond; 42 | var bin = (BinaryExpression)cond.Test; 43 | var leftIsNull = bin.Left.NodeType == ExpressionType.Constant && 44 | ((ConstantExpression)bin.Left).Value == null; 45 | var rightIsNull = bin.Right.NodeType == ExpressionType.Constant && 46 | ((ConstantExpression)bin.Right).Value == null; 47 | if (!leftIsNull && !rightIsNull) 48 | return cond; 49 | var equal = cond.Test.NodeType == ExpressionType.Equal; 50 | var target = leftIsNull ? bin.Right : bin.Left; 51 | if (target!.CanBeNull()) 52 | return cond; 53 | return equal ? cond.IfFalse : cond.IfTrue; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Mapster/Utils/TypeAdapterConfigExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Mapster.Models; 6 | 7 | namespace Mapster.Utils; 8 | 9 | public static class TypeAdapterConfigExtensions 10 | { 11 | public static void ScanInheritedTypes(this TypeAdapterConfig config, Assembly assembly) 12 | { 13 | var types = assembly.GetTypes() 14 | .Where(t => 15 | t.GetInterfaces() 16 | .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>))) 17 | .ToList(); 18 | InterfaceDynamicMapper dynamicMapper = new(config, types); 19 | dynamicMapper.ApplyMappingFromAssembly(); 20 | } 21 | 22 | internal static void ScanInheritedTypes(this TypeAdapterConfig config, List types) 23 | { 24 | types = types.Where(t => 25 | t.GetInterfaces() 26 | .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>))) 27 | .ToList(); 28 | InterfaceDynamicMapper dynamicMapper = new(config, types); 29 | dynamicMapper.ApplyMappingFromAssembly(); 30 | } 31 | 32 | public static bool HasRuleFor(this TypeAdapterConfig config, Type srcType, Type dstType) => 33 | config.RuleMap.ContainsKey(new TypeTuple(srcType, dstType)); 34 | } -------------------------------------------------------------------------------- /src/Mapster/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MapsterMapper/Mapster/bab634544ff7838c1770ad4db2f6d68c4f733a19/src/Mapster/icon.png -------------------------------------------------------------------------------- /src/Pack.bat: -------------------------------------------------------------------------------- 1 | if not exist "Packages" (mkdir "Packages") else (del /F /Q "Packages\*") 2 | dotnet restore Mapster.sln 3 | dotnet msbuild /t:build /p:Configuration=Release /p:GeneratePackageOnBuild=false /p:ExcludeGeneratedDebugSymbol=false Mapster.sln 4 | dotnet pack -c Release -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg -o Packages Mapster.sln -------------------------------------------------------------------------------- /src/Publish.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set /p apikey="Enter Nuget.org API key: " 3 | for /r %%v in (Packages\*.nupkg) do nuget push %%v -ApiKey %apikey% -Source nuget.org -------------------------------------------------------------------------------- /src/Sample.AspNetCore/Models/Course.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace Sample.AspNetCore.Models 5 | { 6 | public class Course 7 | { 8 | [DatabaseGenerated(DatabaseGeneratedOption.None)] 9 | public int CourseID { get; set; } 10 | public string Title { get; set; } 11 | public int Credits { get; set; } 12 | 13 | public ICollection Enrollments { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Sample.AspNetCore/Models/Enrollment.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.AspNetCore.Models 2 | { 3 | public enum Grade 4 | { 5 | A, B, C, D, F 6 | } 7 | 8 | public class Enrollment 9 | { 10 | public int EnrollmentID { get; set; } 11 | public int CourseID { get; set; } 12 | public int StudentID { get; set; } 13 | public Grade? Grade { get; set; } 14 | 15 | public Course Course { get; set; } 16 | public Student Student { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Sample.AspNetCore/Models/SchoolContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | namespace Sample.AspNetCore.Models 8 | { 9 | public class SchoolContext : DbContext 10 | { 11 | public SchoolContext(DbContextOptions options) : base(options) 12 | { 13 | } 14 | 15 | public DbSet Courses { get; set; } 16 | public DbSet Enrollments { get; set; } 17 | public DbSet Students { get; set; } 18 | }} 19 | -------------------------------------------------------------------------------- /src/Sample.AspNetCore/Models/Student.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Sample.AspNetCore.Models 5 | { 6 | public class Student 7 | { 8 | public int ID { get; set; } 9 | public string LastName { get; set; } 10 | public string FirstMidName { get; set; } 11 | public DateTime EnrollmentDate { get; set; } 12 | 13 | public ICollection Enrollments { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Sample.AspNetCore/NameFormatter.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.AspNetCore 2 | { 3 | public class NameFormatter 4 | { 5 | public string Format(string firstName, string lastName) 6 | { 7 | return $"{firstName} {lastName}"; 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Sample.AspNetCore/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Sample.AspNetCore.Models; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Microsoft.Extensions.Hosting; 6 | using Microsoft.Extensions.Logging; 7 | 8 | namespace Sample.AspNetCore 9 | { 10 | public class Program 11 | { 12 | public static void Main(string[] args) 13 | { 14 | var host = CreateHostBuilder(args).Build(); 15 | 16 | using (var scope = host.Services.CreateScope()) 17 | { 18 | var services = scope.ServiceProvider; 19 | try 20 | { 21 | var context = services.GetRequiredService(); 22 | DbInitializer.Initialize(context); 23 | } 24 | catch (Exception ex) 25 | { 26 | var logger = services.GetRequiredService>(); 27 | logger.LogError(ex, "An error occurred while seeding the database."); 28 | } 29 | } 30 | 31 | host.Run(); 32 | } 33 | 34 | public static IHostBuilder CreateHostBuilder(string[] args) => 35 | Host.CreateDefaultBuilder(args) 36 | .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Sample.AspNetCore/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:53541/", 7 | "sslPort": 44378 8 | } 9 | }, 10 | "$schema": "http://json.schemastore.org/launchsettings.json", 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "school/course", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "Sample.AspNetCore": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "school/course", 24 | "environmentVariables": { 25 | "ASPNETCORE_ENVIRONMENT": "Development" 26 | }, 27 | "applicationUrl": "http://localhost:5000" 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Sample.AspNetCore/Sample.AspNetCore.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0;net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Sample.AspNetCore/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Sample.AspNetCore/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Information", 6 | "Microsoft.EntityFrameworkCore": "Information", 7 | "Microsoft.Hosting.Lifetime": "Information" 8 | } 9 | }, 10 | "ConnectionStrings": { 11 | "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true" 12 | }, 13 | "AllowedHosts": "*" 14 | } 15 | -------------------------------------------------------------------------------- /src/Sample.CodeGen/Domains/Course.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.ComponentModel.DataAnnotations.Schema; 4 | 5 | namespace Sample.CodeGen.Domains 6 | { 7 | public class Course 8 | { 9 | [Key, DatabaseGenerated(DatabaseGeneratedOption.None)] 10 | public int CourseID { get; set; } 11 | public string Title { get; set; } 12 | public int Credits { get; set; } 13 | 14 | public ICollection Enrollments { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Sample.CodeGen/Domains/Enrollment.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.CodeGen.Domains 2 | { 3 | public enum Grade 4 | { 5 | A, B, C, D, F 6 | } 7 | 8 | public class Enrollment 9 | { 10 | public int EnrollmentID { get; set; } 11 | public int CourseID { get; set; } 12 | public int StudentID { get; set; } 13 | public Grade? Grade { get; set; } 14 | public Course Course { get; set; } 15 | public Student Student { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Sample.CodeGen/Domains/SchoolContext.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace Sample.CodeGen.Domains 5 | { 6 | public class SchoolContext : DbContext 7 | { 8 | public SchoolContext(DbContextOptions options) : base(options) 9 | { 10 | } 11 | 12 | public DbSet Courses { get; set; } 13 | public DbSet Enrollments { get; set; } 14 | public DbSet Students { get; set; } 15 | }} 16 | -------------------------------------------------------------------------------- /src/Sample.CodeGen/Domains/Student.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace Sample.CodeGen.Domains 6 | { 7 | public class Student 8 | { 9 | [Key] 10 | public int ID { get; set; } 11 | public string? LastName { get; set; } 12 | public string FirstMidName { get; set; } 13 | public DateTime EnrollmentDate { get; set; } 14 | public ICollection Enrollments { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Sample.CodeGen/Mappers/IStudentMapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using Mapster; 4 | using Sample.CodeGen.Domains; 5 | using Sample.CodeGen.Models; 6 | 7 | namespace Sample.CodeGen.Mappers 8 | { 9 | [Mapper] 10 | public interface IStudentMapper 11 | { 12 | Expression> StudentProjection { get; } 13 | Person Map(Student student); 14 | Person Map(Student student, Person person); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Sample.CodeGen/Mappers/StudentMapper.g.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using Sample.CodeGen.Domains; 4 | using Sample.CodeGen.Mappers; 5 | using Sample.CodeGen.Models; 6 | 7 | namespace Sample.CodeGen.Mappers 8 | { 9 | public partial class StudentMapper : IStudentMapper 10 | { 11 | public Expression> StudentProjection => p1 => new Person() 12 | { 13 | ID = p1.ID, 14 | LastName = p1.LastName, 15 | FirstMidName = p1.FirstMidName 16 | }; 17 | public Person Map(Student p2) 18 | { 19 | return p2 == null ? null : new Person() 20 | { 21 | ID = p2.ID, 22 | LastName = p2.LastName, 23 | FirstMidName = p2.FirstMidName 24 | }; 25 | } 26 | public Person Map(Student p3, Person p4) 27 | { 28 | if (p3 == null) 29 | { 30 | return null; 31 | } 32 | Person result = p4 ?? new Person(); 33 | 34 | result.ID = p3.ID; 35 | result.LastName = p3.LastName; 36 | result.FirstMidName = p3.FirstMidName; 37 | return result; 38 | 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/Sample.CodeGen/MappingRegister.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using System.Reflection; 4 | using Mapster; 5 | using Sample.CodeGen.Domains; 6 | using Sample.CodeGen.Models; 7 | 8 | namespace Sample.CodeGen 9 | { 10 | public class MappingRegister : ICodeGenerationRegister 11 | { 12 | public void Register(CodeGenerationConfig config) 13 | { 14 | config.AdaptTo("[name]Dto", MapType.Map | MapType.MapToTarget | MapType.Projection) 15 | .ApplyDefaultRule() 16 | .AlterType(); 17 | 18 | config.AdaptFrom("[name]Add", MapType.Map) 19 | .ApplyDefaultRule() 20 | .IgnoreNoModifyProperties(); 21 | 22 | config.AdaptFrom("[name]Update", MapType.MapToTarget) 23 | .ApplyDefaultRule() 24 | .IgnoreAttributes(typeof(KeyAttribute)) 25 | .IgnoreNoModifyProperties(); 26 | 27 | config.AdaptFrom("[name]Merge", MapType.MapToTarget) 28 | .ApplyDefaultRule() 29 | .IgnoreAttributes(typeof(KeyAttribute)) 30 | .IgnoreNoModifyProperties() 31 | .IgnoreNullValues(true); 32 | 33 | config.GenerateMapper("[name]Mapper") 34 | .ForType() 35 | .ForType(); 36 | } 37 | 38 | } 39 | 40 | static class RegisterExtensions 41 | { 42 | public static AdaptAttributeBuilder ApplyDefaultRule(this AdaptAttributeBuilder builder) 43 | { 44 | return builder 45 | .ForAllTypesInNamespace(Assembly.GetExecutingAssembly(), "Sample.CodeGen.Domains") 46 | .ExcludeTypes(typeof(SchoolContext)) 47 | .ExcludeTypes(type => type.IsEnum) 48 | .AlterType(type => type.IsEnum || Nullable.GetUnderlyingType(type)?.IsEnum == true, typeof(string)) 49 | .ShallowCopyForSameType(true) 50 | .ForType(cfg => cfg.Ignore(it => it.Course)) 51 | .ForType(cfg => cfg.Ignore(it => it.Enrollments)); 52 | } 53 | 54 | public static AdaptAttributeBuilder IgnoreNoModifyProperties(this AdaptAttributeBuilder builder) 55 | { 56 | return builder 57 | .ForType(cfg => cfg.Ignore(it => it.Student)); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Sample.CodeGen/Models/CourseAdd.g.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Sample.CodeGen.Models; 3 | 4 | namespace Sample.CodeGen.Models 5 | { 6 | public partial record CourseAdd 7 | { 8 | public int CourseID { get; set; } 9 | public string Title { get; set; } 10 | public int Credits { get; set; } 11 | public ICollection Enrollments { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Sample.CodeGen/Models/CourseDto.g.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Sample.CodeGen.Models; 3 | 4 | namespace Sample.CodeGen.Models 5 | { 6 | public partial record CourseDto 7 | { 8 | public int CourseID { get; set; } 9 | public string Title { get; set; } 10 | public int Credits { get; set; } 11 | public ICollection Enrollments { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Sample.CodeGen/Models/CourseMerge.g.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Sample.CodeGen.Models; 3 | 4 | namespace Sample.CodeGen.Models 5 | { 6 | public partial record CourseMerge 7 | { 8 | public string Title { get; set; } 9 | public int? Credits { get; set; } 10 | public ICollection Enrollments { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Sample.CodeGen/Models/CourseUpdate.g.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Sample.CodeGen.Models; 3 | 4 | namespace Sample.CodeGen.Models 5 | { 6 | public partial record CourseUpdate 7 | { 8 | public string Title { get; set; } 9 | public int Credits { get; set; } 10 | public ICollection Enrollments { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Sample.CodeGen/Models/EnrollmentAdd.g.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.CodeGen.Models 2 | { 3 | public partial record EnrollmentAdd 4 | { 5 | public int EnrollmentID { get; set; } 6 | public int CourseID { get; set; } 7 | public int StudentID { get; set; } 8 | public string Grade { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/Sample.CodeGen/Models/EnrollmentDto.g.cs: -------------------------------------------------------------------------------- 1 | using Sample.CodeGen.Models; 2 | 3 | namespace Sample.CodeGen.Models 4 | { 5 | public partial record EnrollmentDto 6 | { 7 | public int EnrollmentID { get; set; } 8 | public int CourseID { get; set; } 9 | public int StudentID { get; set; } 10 | public string Grade { get; set; } 11 | public Person Student { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Sample.CodeGen/Models/EnrollmentMerge.g.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.CodeGen.Models 2 | { 3 | public partial record EnrollmentMerge 4 | { 5 | public int? EnrollmentID { get; set; } 6 | public int? CourseID { get; set; } 7 | public int? StudentID { get; set; } 8 | public string Grade { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/Sample.CodeGen/Models/EnrollmentUpdate.g.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.CodeGen.Models 2 | { 3 | public partial record EnrollmentUpdate 4 | { 5 | public int EnrollmentID { get; set; } 6 | public int CourseID { get; set; } 7 | public int StudentID { get; set; } 8 | public string Grade { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/Sample.CodeGen/Models/Person.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.CodeGen.Models 2 | { 3 | public class Person 4 | { 5 | public int ID { get; set; } 6 | public string LastName { get; set; } 7 | public string FirstMidName { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Sample.CodeGen/Models/StudentAdd.g.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sample.CodeGen.Models 4 | { 5 | public partial record StudentAdd 6 | { 7 | public int ID { get; set; } 8 | public string? LastName { get; set; } 9 | public string FirstMidName { get; set; } 10 | public DateTime EnrollmentDate { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Sample.CodeGen/Models/StudentDto.g.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sample.CodeGen.Models 4 | { 5 | public partial record StudentDto 6 | { 7 | public int ID { get; set; } 8 | public string? LastName { get; set; } 9 | public string FirstMidName { get; set; } 10 | public DateTime EnrollmentDate { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Sample.CodeGen/Models/StudentMerge.g.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sample.CodeGen.Models 4 | { 5 | public partial record StudentMerge 6 | { 7 | public string? LastName { get; set; } 8 | public string FirstMidName { get; set; } 9 | public DateTime? EnrollmentDate { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/Sample.CodeGen/Models/StudentUpdate.g.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Sample.CodeGen.Models 4 | { 5 | public partial record StudentUpdate 6 | { 7 | public string? LastName { get; set; } 8 | public string FirstMidName { get; set; } 9 | public DateTime EnrollmentDate { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/Sample.CodeGen/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Hosting; 5 | using Microsoft.Extensions.Logging; 6 | using Sample.CodeGen.Domains; 7 | 8 | namespace Sample.CodeGen 9 | { 10 | public class Program 11 | { 12 | public static void Main(string[] args) 13 | { 14 | var host = CreateHostBuilder(args).Build(); 15 | 16 | using (var scope = host.Services.CreateScope()) 17 | { 18 | var services = scope.ServiceProvider; 19 | try 20 | { 21 | var context = services.GetRequiredService(); 22 | DbInitializer.Initialize(context); 23 | } 24 | catch (Exception ex) 25 | { 26 | var logger = services.GetRequiredService>(); 27 | logger.LogError(ex, "An error occurred while seeding the database."); 28 | } 29 | } 30 | 31 | host.Run(); 32 | } 33 | 34 | public static IHostBuilder CreateHostBuilder(string[] args) => 35 | Host.CreateDefaultBuilder(args) 36 | .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Sample.CodeGen/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:49386", 7 | "sslPort": 44346 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "launchUrl": "school/course", 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "Sample.CodeGen": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "launchUrl": "school/course", 23 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 24 | "environmentVariables": { 25 | "ASPNETCORE_ENVIRONMENT": "Development" 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Sample.CodeGen/Sample.CodeGen.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0;net6.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | PreserveNewest 35 | true 36 | PreserveNewest 37 | 38 | 39 | PreserveNewest 40 | true 41 | PreserveNewest 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/Sample.CodeGen/Startup.cs: -------------------------------------------------------------------------------- 1 | #if NET6_0 2 | using Hellang.Middleware.ProblemDetails; 3 | #endif 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.AspNetCore.OData; 7 | using Microsoft.EntityFrameworkCore; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.DependencyInjection; 10 | using Sample.CodeGen.Domains; 11 | 12 | namespace Sample.CodeGen 13 | { 14 | public class Startup 15 | { 16 | public Startup(IConfiguration configuration) 17 | { 18 | Configuration = configuration; 19 | } 20 | 21 | public IConfiguration Configuration { get; } 22 | 23 | // This method gets called by the runtime. Use this method to add services to the container. 24 | // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 25 | public void ConfigureServices(IServiceCollection services) 26 | { 27 | services.AddControllers(opts => opts.EnableEndpointRouting = false) 28 | .AddOData(options => options.Select().Filter().OrderBy()) 29 | .AddNewtonsoftJson(); 30 | services.AddDbContext(options => 31 | options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); 32 | 33 | services.AddProblemDetails(); 34 | services.Scan(selector => selector.FromCallingAssembly() 35 | .AddClasses().AsMatchingInterface().WithSingletonLifetime()); 36 | } 37 | 38 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 39 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 40 | { 41 | #if NET6_0 42 | app.UseProblemDetails(); 43 | #endif 44 | app.UseRouting(); 45 | app.UseAuthorization(); 46 | app.UseMvc(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Sample.CodeGen/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Sample.CodeGen/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Information", 6 | "Microsoft.EntityFrameworkCore": "Information", 7 | "Microsoft.Hosting.Lifetime": "Information" 8 | } 9 | }, 10 | "ConnectionStrings": { 11 | "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true" 12 | }, 13 | "AllowedHosts": "*" 14 | } 15 | -------------------------------------------------------------------------------- /src/TemplateTest/FooTest.cs: -------------------------------------------------------------------------------- 1 | using ExpressionDebugger; 2 | using Mapster; 3 | using Microsoft.VisualStudio.TestTools.UnitTesting; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace TemplateTest 8 | { 9 | [TestClass] 10 | public class FooTest 11 | { 12 | [TestMethod] 13 | public void TestCreateMapExpression() 14 | { 15 | TypeAdapterConfig.GlobalSettings.SelfContainedCodeGeneration = true; 16 | var foo = default(Foo); 17 | var def = new ExpressionDefinitions 18 | { 19 | IsStatic = true, 20 | MethodName = "Map", 21 | Namespace = "Benchmark", 22 | TypeName = "FooMapper" 23 | }; 24 | var code = foo.BuildAdapter() 25 | .CreateMapExpression() 26 | .ToScript(def); 27 | code = code.Replace("TypeAdapter.Map.Invoke", "Map"); 28 | 29 | Assert.IsNotNull(code); 30 | } 31 | } 32 | 33 | public class Foo 34 | { 35 | public string Name { get; set; } 36 | 37 | public int Int32 { get; set; } 38 | 39 | public long Int64 { set; get; } 40 | 41 | public int? NullInt { get; set; } 42 | 43 | public float Floatn { get; set; } 44 | 45 | public double Doublen { get; set; } 46 | 47 | public DateTime DateTime { get; set; } 48 | 49 | public Foo Foo1 { get; set; } 50 | 51 | public IEnumerable Foos { get; set; } 52 | 53 | public Foo[] FooArr { get; set; } 54 | 55 | public int[] IntArr { get; set; } 56 | 57 | public IEnumerable Ints { get; set; } 58 | } 59 | } -------------------------------------------------------------------------------- /src/TemplateTest/TemplateTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0;net6.0 5 | enable 6 | 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | --------------------------------------------------------------------------------