Skip to content

Commit b56ff38

Browse files
committed
fix #292 support MemberSide for AdaptMemberAttribute
fix flattening with poco property type
1 parent 39ee1ba commit b56ff38

File tree

9 files changed

+85
-25
lines changed

9 files changed

+85
-25
lines changed

src/Mapster.Core/Attributes/AdaptMemberAttribute.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,17 @@ namespace Mapster
88
public class AdaptMemberAttribute : Attribute
99
{
1010
public string? Name { get; set; }
11+
public MemberSide? Side { get; set; }
1112

1213
public AdaptMemberAttribute() { }
1314
public AdaptMemberAttribute(string name)
1415
{
1516
this.Name = name;
1617
}
18+
public AdaptMemberAttribute(string name, MemberSide side)
19+
{
20+
this.Name = name;
21+
this.Side = side;
22+
}
1723
}
1824
}

src/Mapster.Tests/WhenUsingAttribute.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ public void Using_Attributes()
2121
dto.Name.ShouldBeNull();
2222
}
2323

24+
[TestMethod]
25+
public void Specify_MemberSide()
26+
{
27+
var user = new User {UserIdentification = 123};
28+
var dto = user.Adapt<UserDto>();
29+
var info = dto.Adapt<UserInfo>();
30+
info.UserId.ShouldBe(123);
31+
}
32+
2433
public class SimplePoco
2534
{
2635
public SimplePoco(Guid id) { this.id = id; }
@@ -38,5 +47,20 @@ public class SimpleDto
3847
public string Name { get; set; }
3948
}
4049

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+
}
4165
}
4266
}

src/Mapster.Tool/Program.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ private static void CreateModel(ModelOptions opt, Type type, BaseAdaptAttribute
181181
foreach (var member in properties)
182182
{
183183
var adaptMember = member.GetCustomAttribute<AdaptMemberAttribute>();
184+
if (!isTwoWays && adaptMember?.Side != null && adaptMember.Side != side)
185+
adaptMember = null;
184186
var propType = GetPropertyType(member, getPropType(member), attr.GetType(), opt.Namespace);
185187
translator.Properties.Add(new PropertyDefinitions
186188
{

src/Mapster/Settings/GetMemberName.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ namespace Mapster
55
{
66
public static class GetMemberName
77
{
8-
public static readonly Func<IMemberModel, string?> AdaptMember = model => model.GetCustomAttributeFromData<AdaptMemberAttribute>()?.Name;
8+
public static readonly Func<IMemberModel, MemberSide, string?> AdaptMember = (model, side) =>
9+
{
10+
var memberAttr = model.GetCustomAttributeFromData<AdaptMemberAttribute>();
11+
if (memberAttr == null)
12+
return null;
13+
return memberAttr.Side == null || memberAttr.Side == side ? memberAttr.Name : null;
14+
};
915
}
1016
}

src/Mapster/Settings/ShouldMapMember.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ public static class ShouldMapMember
1919
return null;
2020
return ignoreAttr.Side == null || ignoreAttr.Side == side ? (bool?) false : null;
2121
};
22-
public static readonly Func<IMemberModel, MemberSide, bool?> AllowAdaptMember = (model, _) => model.HasCustomAttribute<AdaptMemberAttribute>() ? (bool?)true : null;
22+
public static readonly Func<IMemberModel, MemberSide, bool?> AllowAdaptMember = (model, side) =>
23+
{
24+
var memberAttr = model.GetCustomAttributeFromData<AdaptMemberAttribute>();
25+
if (memberAttr == null)
26+
return null;
27+
return memberAttr.Side == null || memberAttr.Side == side ? (bool?) true : null;
28+
};
2329
}
2430
}

src/Mapster/Settings/ValueAccessingStrategy.cs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,10 @@ public static class ValueAccessingStrategy
7373
{
7474
var members = source.Type.GetFieldsAndProperties(true);
7575
var strategy = arg.Settings.NameMatchingStrategy;
76-
var destinationMemberName = destinationMember.GetMemberName(arg.Settings.GetMemberNames, strategy.DestinationMemberNameConverter);
76+
var destinationMemberName = destinationMember.GetMemberName(MemberSide.Destination, arg.Settings.GetMemberNames, strategy.DestinationMemberNameConverter);
7777
return members
7878
.Where(member => member.ShouldMapMember(arg, MemberSide.Source))
79-
.Where(member => member.GetMemberName(arg.Settings.GetMemberNames, strategy.SourceMemberNameConverter) == destinationMemberName)
79+
.Where(member => member.GetMemberName(MemberSide.Source, arg.Settings.GetMemberNames, strategy.SourceMemberNameConverter) == destinationMemberName)
8080
.Select(member => member.GetExpression(source))
8181
.FirstOrDefault();
8282
}
@@ -86,7 +86,7 @@ public static class ValueAccessingStrategy
8686
if (arg.MapType == MapType.Projection)
8787
return null;
8888
var strategy = arg.Settings.NameMatchingStrategy;
89-
var destinationMemberName = "Get" + destinationMember.GetMemberName(arg.Settings.GetMemberNames, strategy.DestinationMemberNameConverter);
89+
var destinationMemberName = "Get" + destinationMember.GetMemberName(MemberSide.Destination, arg.Settings.GetMemberNames, strategy.DestinationMemberNameConverter);
9090
var getMethod = Array.Find(source.Type.GetMethods(BindingFlags.Public | BindingFlags.Instance), m => strategy.SourceMemberNameConverter(m.Name) == destinationMemberName && m.GetParameters().Length == 0);
9191
if (getMethod == null)
9292
return null;
@@ -98,7 +98,7 @@ public static class ValueAccessingStrategy
9898
private static Expression? FlattenMemberFn(Expression source, IMemberModel destinationMember, CompileArgument arg)
9999
{
100100
var strategy = arg.Settings.NameMatchingStrategy;
101-
var destinationMemberName = destinationMember.GetMemberName(arg.Settings.GetMemberNames, strategy.DestinationMemberNameConverter);
101+
var destinationMemberName = destinationMember.GetMemberName(MemberSide.Destination, arg.Settings.GetMemberNames, strategy.DestinationMemberNameConverter);
102102
return GetDeepFlattening(source, destinationMemberName, arg);
103103
}
104104

@@ -110,7 +110,11 @@ public static class ValueAccessingStrategy
110110
{
111111
if (!member.ShouldMapMember(arg, MemberSide.Source))
112112
continue;
113-
var sourceMemberName = member.GetMemberName(arg.Settings.GetMemberNames, strategy.SourceMemberNameConverter);
113+
114+
var sourceMemberName = member.GetMemberName(MemberSide.Source, arg.Settings.GetMemberNames, strategy.SourceMemberNameConverter);
115+
if (string.Equals(propertyName, sourceMemberName))
116+
return member.GetExpression(source);
117+
114118
var propertyType = member.Type;
115119
if (propertyName.StartsWith(sourceMemberName) &&
116120
(propertyType.IsPoco() || propertyType.IsRecordType()))
@@ -121,24 +125,21 @@ public static class ValueAccessingStrategy
121125
continue;
122126
return ifTrue;
123127
}
124-
125-
if (string.Equals(propertyName, sourceMemberName))
126-
return member.GetExpression(source);
127128
}
128129
return null;
129130
}
130131

131132
internal static IEnumerable<InvokerModel> FindUnflatteningPairs(Expression source, IMemberModel destinationMember, CompileArgument arg)
132133
{
133134
var strategy = arg.Settings.NameMatchingStrategy;
134-
var destinationMemberName = destinationMember.GetMemberName(arg.Settings.GetMemberNames, strategy.DestinationMemberNameConverter);
135+
var destinationMemberName = destinationMember.GetMemberName(MemberSide.Destination, arg.Settings.GetMemberNames, strategy.DestinationMemberNameConverter);
135136
var members = source.Type.GetFieldsAndProperties(true);
136137

137138
foreach (var member in members)
138139
{
139140
if (!member.ShouldMapMember(arg, MemberSide.Source))
140141
continue;
141-
var sourceMemberName = member.GetMemberName(arg.Settings.GetMemberNames, strategy.SourceMemberNameConverter);
142+
var sourceMemberName = member.GetMemberName(MemberSide.Source, arg.Settings.GetMemberNames, strategy.SourceMemberNameConverter);
142143
if (!sourceMemberName.StartsWith(destinationMemberName) || sourceMemberName == destinationMemberName)
143144
continue;
144145
foreach (var prop in GetDeepUnflattening(destinationMember, sourceMemberName.Substring(destinationMemberName.Length).TrimStart('_'), arg))
@@ -160,20 +161,20 @@ private static IEnumerable<string> GetDeepUnflattening(IMemberModel destinationM
160161
{
161162
if (!member.ShouldMapMember(arg, MemberSide.Destination))
162163
continue;
163-
var destMemberName = member.GetMemberName(arg.Settings.GetMemberNames, strategy.DestinationMemberNameConverter);
164+
var destMemberName = member.GetMemberName(MemberSide.Destination, arg.Settings.GetMemberNames, strategy.DestinationMemberNameConverter);
164165
var propertyType = member.Type;
165-
if (propertyName.StartsWith(destMemberName) &&
166+
if (string.Equals(propertyName, destMemberName))
167+
{
168+
yield return member.Name;
169+
}
170+
else if (propertyName.StartsWith(destMemberName) &&
166171
(propertyType.IsPoco() || propertyType.IsRecordType()))
167172
{
168173
foreach (var prop in GetDeepUnflattening(member, propertyName.Substring(destMemberName.Length).TrimStart('_'), arg))
169174
{
170175
yield return member.Name + "." + prop;
171176
}
172177
}
173-
else if (string.Equals(propertyName, destMemberName))
174-
{
175-
yield return member.Name;
176-
}
177178
}
178179
}
179180

@@ -184,7 +185,7 @@ private static IEnumerable<string> GetDeepUnflattening(IMemberModel destinationM
184185
return null;
185186

186187
var strategy = arg.Settings.NameMatchingStrategy;
187-
var destinationMemberName = destinationMember.GetMemberName(arg.Settings.GetMemberNames, strategy.DestinationMemberNameConverter);
188+
var destinationMemberName = destinationMember.GetMemberName(MemberSide.Destination, arg.Settings.GetMemberNames, strategy.DestinationMemberNameConverter);
188189
var key = Expression.Constant(destinationMemberName);
189190
var args = dictType.GetGenericArguments();
190191
if (strategy.SourceMemberNameConverter != MapsterHelper.Identity)

src/Mapster/TypeAdapterSetter.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,15 @@ public static TSetter AvoidInlineMapping<TSetter>(this TSetter setter, bool valu
207207
return setter;
208208
}
209209

210-
public static TSetter GetMemberName<TSetter>(this TSetter setter, Func<IMemberModel, string> func) where TSetter : TypeAdapterSetter
210+
public static TSetter GetMemberName<TSetter>(this TSetter setter, Func<IMemberModel, string?> func) where TSetter : TypeAdapterSetter
211+
{
212+
setter.CheckCompiled();
213+
214+
setter.Settings.GetMemberNames.Add((member, _) => func(member));
215+
return setter;
216+
}
217+
218+
public static TSetter GetMemberName<TSetter>(this TSetter setter, Func<IMemberModel, MemberSide, string?> func) where TSetter : TypeAdapterSetter
211219
{
212220
setter.CheckCompiled();
213221

@@ -816,13 +824,20 @@ public TwoWaysTypeAdapterSetter<TSource, TDestination> AvoidInlineMapping(bool v
816824
return this;
817825
}
818826

819-
public TwoWaysTypeAdapterSetter<TSource, TDestination> GetMemberName(Func<IMemberModel, string> func)
827+
public TwoWaysTypeAdapterSetter<TSource, TDestination> GetMemberName(Func<IMemberModel, string?> func)
820828
{
821829
SourceToDestinationSetter.GetMemberName(func);
822830
DestinationToSourceSetter.GetMemberName(func);
823831
return this;
824832
}
825833

834+
public TwoWaysTypeAdapterSetter<TSource, TDestination> GetMemberName(Func<IMemberModel, MemberSide, string?> func)
835+
{
836+
SourceToDestinationSetter.GetMemberName(func);
837+
DestinationToSourceSetter.GetMemberName((model, side) => func(model, side == MemberSide.Source ? MemberSide.Destination : MemberSide.Source));
838+
return this;
839+
}
840+
826841
public TwoWaysTypeAdapterSetter<TSource, TDestination> MapToConstructor(bool value)
827842
{
828843
SourceToDestinationSetter.MapToConstructor(value);

src/Mapster/TypeAdapterSettings.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ public List<TypeTuple> Includes
106106
{
107107
get => Get(nameof(Includes), () => new List<TypeTuple>());
108108
}
109-
public List<Func<IMemberModel, string?>> GetMemberNames
109+
public List<Func<IMemberModel, MemberSide, string?>> GetMemberNames
110110
{
111-
get => Get(nameof(GetMemberNames), () => new List<Func<IMemberModel, string?>>());
111+
get => Get(nameof(GetMemberNames), () => new List<Func<IMemberModel, MemberSide, string?>>());
112112
}
113113
public List<Func<IMemberModel, bool>> UseDestinationValues
114114
{

src/Mapster/Utils/ReflectionUtils.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,9 +315,9 @@ public static bool UseDestinationValue(this IMemberModel member, CompileArgument
315315
return predicates.Any(predicate => predicate(member));
316316
}
317317

318-
public static string GetMemberName(this IMemberModel member, List<Func<IMemberModel, string?>> getMemberNames, Func<string, string> nameConverter)
318+
public static string GetMemberName(this IMemberModel member, MemberSide side, List<Func<IMemberModel, MemberSide, string?>> getMemberNames, Func<string, string> nameConverter)
319319
{
320-
var memberName = getMemberNames.Select(predicate => predicate(member))
320+
var memberName = getMemberNames.Select(func => func(member, side))
321321
.FirstOrDefault(name => name != null)
322322
?? member.Name;
323323

0 commit comments

Comments
 (0)