Skip to content

Commit c5a65eb

Browse files
committed
Add Inherits Lasyload and Test
1 parent 155a723 commit c5a65eb

File tree

6 files changed

+179
-2
lines changed

6 files changed

+179
-2
lines changed

src/Mapster.Tests/WhenMappingWithExplicitInheritance.cs

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,77 @@ public void Invalid_Destination_Cast_Throws_Exception()
130130

131131
}
132132

133+
[TestMethod]
134+
public void InheritsLasyLoad__IsWork()
135+
{
136+
TypeAdapterConfig<DerivedPoco, DerivedDto>.NewConfig()
137+
.Inherits<SimplePoco, SimpleDto>()
138+
.Compile();
139+
140+
TypeAdapterConfig<SimplePoco, SimpleDto>.NewConfig()
141+
.Inherits<RootPoco, RootDto>()
142+
.Ignore(dest => dest.Name)
143+
.Compile();
144+
145+
TypeAdapterConfig<RootPoco, RootDto>.NewConfig()
146+
.Map(dest => dest.NumberDto, src => 42)
147+
.Compile();
148+
149+
var source = new DerivedPoco
150+
{
151+
Id = new Guid(),
152+
Name = "SourceName"
153+
};
154+
155+
var dto = TypeAdapter.Adapt<DerivedDto>(source);
156+
157+
dto.Id.ShouldBe(source.Id);
158+
dto.Name.ShouldBe("SourceName"); // Inherits Ignore not work
159+
dto.NumberDto.ShouldBe(0); // Inherits not work
160+
161+
Setup(); // clean config
162+
163+
TypeAdapterConfig<DerivedPoco, DerivedDto>.NewConfig()
164+
.InheritsLazy<SimplePoco, SimpleDto>()
165+
.Compile();
166+
167+
TypeAdapterConfig<SimplePoco, SimpleDto>.NewConfig()
168+
.InheritsLazy<RootPoco, RootDto>()
169+
.Ignore(dest => dest.Name)
170+
.Compile();
171+
172+
TypeAdapterConfig<RootPoco, RootDto>.NewConfig()
173+
.Map(dest => dest.NumberDto, src => 42)
174+
.Compile();
175+
176+
dto = TypeAdapter.Adapt<DerivedDto>(source);
177+
178+
dto.Id.ShouldBe(source.Id);
179+
dto.Name.ShouldBeNull(); // InheritsLazy Ignore is work
180+
dto.NumberDto.ShouldBe(42); // InheritsLazy is work
181+
}
182+
183+
133184
#region TestMethod Classes
134185

135-
public class SimplePoco
186+
public class RootPoco
187+
{
188+
public int Number { get; set; }
189+
}
190+
191+
public class RootDto
192+
{
193+
public int NumberDto { get; set; }
194+
}
195+
196+
197+
public class SimplePoco: RootPoco
136198
{
137199
public Guid Id { get; set; }
138200
public string Name { get; set; }
139201
}
140202

141-
public class SimpleDto
203+
public class SimpleDto : RootDto
142204
{
143205
public Guid Id { get; set; }
144206
public string Name { get; set; }

src/Mapster/Models/TypeTuple.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,50 @@ public TypeTuple(Type source, Type destination)
4040
Destination = destination;
4141
}
4242
}
43+
44+
public class InheritsTypeTuple : IEquatable<InheritsTypeTuple>
45+
{
46+
public bool Equals(InheritsTypeTuple other)
47+
{
48+
return Source == other.Source && Destination == other.Destination;
49+
}
50+
51+
public override bool Equals(object obj)
52+
{
53+
if (!(obj is InheritsTypeTuple))
54+
return false;
55+
return Equals((InheritsTypeTuple)obj);
56+
}
57+
58+
public override int GetHashCode()
59+
{
60+
return (Source.GetHashCode() << 16) ^ (Destination.GetHashCode() & 65535);
61+
}
62+
63+
public static bool operator ==(InheritsTypeTuple left, InheritsTypeTuple right)
64+
{
65+
return left.Equals(right);
66+
}
67+
68+
public static bool operator !=(InheritsTypeTuple left, InheritsTypeTuple right)
69+
{
70+
return !left.Equals(right);
71+
}
72+
73+
public Type Source { get; }
74+
public Type Destination { get; }
75+
public bool IsLoading { get; private set; }
76+
77+
public void IsUploaded()
78+
{
79+
IsLoading = true;
80+
}
81+
82+
public InheritsTypeTuple(Type source, Type destination)
83+
{
84+
Source = source;
85+
Destination = destination;
86+
IsLoading = false;
87+
}
88+
}
4389
}

src/Mapster/TypeAdapterConfig.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,12 +317,41 @@ public Func<TSource, TDestination> GetMapFunction<TSource, TDestination>()
317317
}
318318
internal Delegate GetMapFunction(Type sourceType, Type destinationType)
319319
{
320+
LoadInheritedRulesLazy(new TypeTuple(sourceType, destinationType));
321+
320322
var key = new TypeTuple(sourceType, destinationType);
321323
if (!_mapDict.TryGetValue(key, out var del))
322324
del = AddToHash(_mapDict, key, tuple => Compiler(CreateMapExpression(tuple, MapType.Map)));
323325
return del;
324326
}
325327

328+
private void LoadInheritedRulesLazy(TypeTuple types)
329+
{
330+
if (RuleMap.TryGetValue(types, out var rule))
331+
{
332+
if (rule.Settings.InheritsTypeTuples.Count > 0)
333+
{
334+
LoadInheritedRules(rule, rule.Settings.InheritsTypeTuples);
335+
}
336+
}
337+
}
338+
private void LoadInheritedRules(TypeAdapterRule rule, IEnumerable<InheritsTypeTuple> inheritedTypes)
339+
{
340+
foreach (var typeTuple in inheritedTypes.Where(t => !t.IsLoading))
341+
{
342+
if (RuleMap.TryGetValue(new TypeTuple(typeTuple.Source, typeTuple.Destination), out var parentRule))
343+
{
344+
rule.LoadLasyInherits(parentRule);
345+
typeTuple.IsUploaded();
346+
}
347+
if (parentRule != null && parentRule.Settings.InheritsTypeTuples.Any())
348+
{
349+
LoadInheritedRules(rule, parentRule.Settings.InheritsTypeTuples);
350+
}
351+
}
352+
}
353+
354+
326355
private readonly ConcurrentDictionary<TypeTuple, Delegate> _mapToTargetDict = new ConcurrentDictionary<TypeTuple, Delegate>();
327356
public Func<TSource, TDestination, TDestination> GetMapToTargetFunction<TSource, TDestination>()
328357
{
@@ -331,6 +360,9 @@ public Func<TSource, TDestination, TDestination> GetMapToTargetFunction<TSource,
331360
internal Delegate GetMapToTargetFunction(Type sourceType, Type destinationType)
332361
{
333362
var key = new TypeTuple(sourceType, destinationType);
363+
364+
LoadInheritedRulesLazy(key);
365+
334366
if (!_mapToTargetDict.TryGetValue(key, out var del))
335367
del = AddToHash(_mapToTargetDict, key, tuple => Compiler(CreateMapExpression(tuple, MapType.MapToTarget)));
336368
return del;
@@ -346,6 +378,9 @@ internal Expression<Func<TSource, TDestination>> GetProjectionExpression<TSource
346378
internal MethodCallExpression GetProjectionCallExpression(Type sourceType, Type destinationType)
347379
{
348380
var key = new TypeTuple(sourceType, destinationType);
381+
382+
LoadInheritedRulesLazy(key);
383+
349384
if (!_projectionDict.TryGetValue(key, out var del))
350385
del = AddToHash(_projectionDict, key, CreateProjectionCallExpression);
351386
return del;
@@ -355,6 +390,9 @@ internal MethodCallExpression GetProjectionCallExpression(Type sourceType, Type
355390
public Func<object, TDestination> GetDynamicMapFunction<TDestination>(Type sourceType)
356391
{
357392
var key = new TypeTuple(sourceType, typeof(TDestination));
393+
394+
LoadInheritedRulesLazy(key);
395+
358396
if (!_dynamicMapDict.TryGetValue(key, out var del))
359397
del = AddToHash(_dynamicMapDict, key, tuple => Compiler(CreateDynamicMapExpression(tuple)));
360398
return (Func<object, TDestination>)del;

src/Mapster/TypeAdapterRule.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,10 @@ public class TypeAdapterRule
66
{
77
public Func<PreCompileArgument, int?> Priority { get; set; }
88
public TypeAdapterSettings Settings { get; set; }
9+
10+
public void LoadLasyInherits(TypeAdapterRule rule)
11+
{
12+
this.Settings.Apply(rule.Settings);
13+
}
914
}
1015
}

src/Mapster/TypeAdapterSetter.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,26 @@ public TypeAdapterSetter<TSource, TDestination> Inherits<TBaseSource, TBaseDesti
828828
return this;
829829
}
830830

831+
public TypeAdapterSetter<TSource, TDestination> InheritsLazy<TBaseSource, TBaseDestination>()
832+
{
833+
this.CheckCompiled();
834+
835+
Type baseSourceType = typeof(TBaseSource);
836+
Type baseDestinationType = typeof(TBaseDestination);
837+
838+
if (!baseSourceType.GetTypeInfo().IsAssignableFrom(typeof(TSource).GetTypeInfo()))
839+
throw new InvalidCastException("In order to use inherits, TSource must be inherited from TBaseSource.");
840+
841+
if (!baseDestinationType.GetTypeInfo().IsAssignableFrom(typeof(TDestination).GetTypeInfo()))
842+
throw new InvalidCastException("In order to use inherits, TDestination must be inherited from TBaseDestination.");
843+
844+
Settings.InheritsTypeTuples.Add(new InheritsTypeTuple(baseSourceType, baseDestinationType));
845+
846+
847+
return this;
848+
}
849+
850+
831851
public TypeAdapterSetter<TSource, TDestination> Fork(Action<TypeAdapterConfig> action)
832852
{
833853
this.CheckCompiled();

src/Mapster/TypeAdapterSettings.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,12 @@ public List<InvokerModel> Resolvers
117117
{
118118
get => Get(nameof(Resolvers), () => new List<InvokerModel>());
119119
}
120+
121+
public HashSet<InheritsTypeTuple> InheritsTypeTuples
122+
{
123+
get => Get(nameof(InheritsTypeTuples), () => new HashSet<InheritsTypeTuple>());
124+
}
125+
120126
public List<object> ExtraSources
121127
{
122128
get => Get(nameof(ExtraSources), () => new List<object>());

0 commit comments

Comments
 (0)