Skip to content

Commit

Permalink
fix #282 map error on record type with empty ctor
Browse files Browse the repository at this point in the history
  • Loading branch information
chaowlert committed Nov 26, 2020
1 parent b1137f5 commit f191ea5
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 4 deletions.
69 changes: 69 additions & 0 deletions src/Mapster.Tests/WhenMappingCollections.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Shouldly;
Expand Down Expand Up @@ -262,5 +263,73 @@ IEnumerable<int> GetInts()
GetInts().Adapt<int[,]>();
i.ShouldBe(1);
}

[TestMethod]
public void TestEnumList()
{
var testClass = new CloneTestEnumContainerListContainer
{
List1 = new List<CloneTestEnumContainer>
{
new CloneTestEnumContainer
{
Type = CloneTestEnum.Value1,
Value = 500
}
},
List2 = new List<CloneTestEnumContainer>
{
new CloneTestEnumContainer
{
Type = CloneTestEnum.Value5,
Value = 500
}
}
};

var cloneTest = testClass.Adapt<CloneTestEnumContainerListContainer>();
foreach (var paymentCompoent in testClass.CombinedLists)
{
cloneTest.CombinedLists.ShouldContain(x => x.Type == paymentCompoent.Type && x.Value == paymentCompoent.Value);
}
}

#region TestClass

[Flags]
public enum CloneTestEnum
{
Value1 = 1,
Value2 = 2,
Value3 = 100,
Value4 = 200,
Value5 = 300
}

public class CloneTestEnumContainer
{
public CloneTestEnumContainer()
{

}

public CloneTestEnumContainer(CloneTestEnum type, decimal value)
{
Type = type;
Value = value;
}

public CloneTestEnum Type { get; set; }
public decimal Value { get; set; }
}

public class CloneTestEnumContainerListContainer
{
public List<CloneTestEnumContainer> List1 { get; set; } = new List<CloneTestEnumContainer>(); //parts of the pricing calcs that need VAT added
public List<CloneTestEnumContainer> List2 { get; set; } = new List<CloneTestEnumContainer>(); //parts of the pricing calcs that must NOT have VAT
public ReadOnlyCollection<CloneTestEnumContainer> CombinedLists => List1.Concat(List2).ToList().AsReadOnly();
}

#endregion
}
}
17 changes: 13 additions & 4 deletions src/Mapster/Utils/ReflectionUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ public static IEnumerable<Type> GetAllInterfaces(this Type interfaceType)
{
var allInterfaces = new HashSet<Type>();
var interfaceQueue = new Queue<Type>();

allInterfaces.Add(interfaceType);
yield return interfaceType;

interfaceQueue.Enqueue(interfaceType);
while (interfaceQueue.Count > 0)
{
Expand All @@ -96,11 +99,12 @@ public static IEnumerable<Type> GetAllInterfaces(this Type interfaceType)
{
if (allInterfaces.Contains(subInterface))
continue;

allInterfaces.Add(subInterface);
yield return subInterface;
interfaceQueue.Enqueue(subInterface);
}
}
return allInterfaces;
}

public static bool IsCollection(this Type type)
Expand Down Expand Up @@ -171,16 +175,21 @@ public static bool IsRecordType(this Type type)
props.All(p => p.SetterModifier != AccessModifier.Public))
return true;

//1 non-empty constructor
var ctors = type.GetConstructors().Where(ctor => ctor.GetParameters().Length > 0).ToList();
//1 constructor
var ctors = type.GetConstructors().ToList();
if (ctors.Count != 1)
return false;

//ctor must not empty
var ctorParams = ctors[0].GetParameters();
if (ctorParams.Length == 0)
return false;

//all parameters should match getter
return props.All(prop =>
{
var name = prop.Name.ToPascalCase();
return ctors[0].GetParameters().Any(p => p.ParameterType == prop.Type && p.Name?.ToPascalCase() == name);
return ctorParams.Any(p => p.ParameterType == prop.Type && p.Name?.ToPascalCase() == name);
});
}

Expand Down

0 comments on commit f191ea5

Please sign in to comment.