Skip to content

Commit fc1bd5c

Browse files
committed
Add better support for using converters everywhere
1 parent bbf0ae9 commit fc1bd5c

3 files changed

Lines changed: 52 additions & 26 deletions

File tree

src/ServiceStack.Text/AutoMappingUtils.cs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,9 @@ public static GetMemberDelegate GetConverter(Type fromType, Type toType)
6363
? converter
6464
: null;
6565
}
66-
67-
public static T ConvertTo<T>(this object from)
66+
67+
public static T ConvertTo<T>(this object from) => from.ConvertTo<T>(skipConverters:false);
68+
public static T ConvertTo<T>(this object from, bool skipConverters)
6869
{
6970
if (from == null)
7071
return default(T);
@@ -73,7 +74,7 @@ public static T ConvertTo<T>(this object from)
7374
if (fromType == typeof(T))
7475
return (T)from;
7576

76-
return (T)ConvertTo(from, typeof(T));
77+
return (T)ConvertTo(from, typeof(T), skipConverters);
7778
}
7879

7980
public static T CreateCopy<T>(this T from)
@@ -83,7 +84,7 @@ public static T CreateCopy<T>(this T from)
8384

8485
if (typeof(IEnumerable).IsAssignableFrom(typeof(T)))
8586
{
86-
var listResult = TryConvertCollections(from.GetType(), typeof(T), from);
87+
var listResult = TranslateListWithElements.TryTranslateCollections(from.GetType(), typeof(T), from);
8788
return (T)listResult;
8889
}
8990

@@ -97,29 +98,38 @@ public static To ThenDo<To>(this To to, Action<To> fn)
9798
return to;
9899
}
99100

100-
public static object ConvertTo(this object from, Type type)
101+
public static object ConvertTo(this object from, Type toType) => from.ConvertTo(toType, skipConverters: false);
102+
public static object ConvertTo(this object from, Type toType, bool skipConverters)
101103
{
102104
if (from == null)
103105
return null;
104106

105-
if (from.GetType() == type)
107+
var fromType = from.GetType();
108+
if (fromType == toType)
106109
return from;
107110

108-
if (from.GetType().IsValueType || type.IsValueType)
109-
return ChangeValueType(from, type);
111+
if (!skipConverters)
112+
{
113+
var converter = GetConverter(fromType, toType);
114+
if (converter != null)
115+
return converter(from);
116+
}
117+
118+
if (fromType.IsValueType || toType.IsValueType)
119+
return ChangeValueType(from, toType);
110120

111121
if (from is string str)
112-
return TypeSerializer.DeserializeFromString(str, type);
122+
return TypeSerializer.DeserializeFromString(str, toType);
113123
if (from is ReadOnlyMemory<char> rom)
114-
return TypeSerializer.DeserializeFromSpan(type, rom.Span);
124+
return TypeSerializer.DeserializeFromSpan(toType, rom.Span);
115125

116-
if (typeof(IEnumerable).IsAssignableFrom(type))
126+
if (typeof(IEnumerable).IsAssignableFrom(toType))
117127
{
118-
var listResult = TryConvertCollections(from.GetType(), type, from);
128+
var listResult = TryConvertCollections(fromType, toType, from);
119129
return listResult;
120130
}
121131

122-
var to = type.CreateInstance();
132+
var to = toType.CreateInstance();
123133
return to.PopulateWithNonDefaultValues(from);
124134
}
125135

tests/ServiceStack.Text.Tests/AutoMappingCustomConverterTests.cs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -141,29 +141,41 @@ public void Should_Not_Throw_Exception_When_Multiple_Same_Type_CustomTypeConvert
141141
[Test]
142142
public void Can_Convert_POCO_collections_with_custom_Converter()
143143
{
144-
AutoMappingUtils.RegisterConverter((User from) => from.ConvertTo<UserDto>());
144+
AutoMappingUtils.RegisterConverter((User from) => {
145+
var to = from.ConvertTo<UserDto>(skipConverters:true); // avoid infinite recursion
146+
to.FirstName += "!";
147+
to.LastName += "!";
148+
return to;
149+
});
145150
AutoMappingUtils.RegisterConverter((Car from) => $"{from.Name} ({from.Age})");
146-
151+
152+
var user = new User {
153+
FirstName = "John",
154+
LastName = "Doe",
155+
Car = new Car { Name = "BMW X6", Age = 3 }
156+
};
147157
var users = new UsersData {
148158
Id = 1,
149-
Users = new List<User> {
150-
new User {
151-
FirstName = "John",
152-
LastName = "Doe",
153-
Car = new Car { Name = "BMW X6", Age = 3 }
154-
}
155-
}
159+
User = user,
160+
Users = new List<User> { user }
156161
};
157162

158163
var dtoUsers = users.ConvertTo<UsersDto>();
159164

160165
dtoUsers.PrintDump();
161166

162167
Assert.That(dtoUsers.Id, Is.EqualTo(users.Id));
163-
Assert.That(dtoUsers.Users[0].FirstName, Is.EqualTo(users.Users[0].FirstName));
164-
Assert.That(dtoUsers.Users[0].LastName, Is.EqualTo(users.Users[0].LastName));
165-
Assert.That(dtoUsers.Users[0].Car, Is.EqualTo("BMW X6 (3)"));
166-
168+
169+
void AssertUser(UserDto userDto)
170+
{
171+
Assert.That(userDto.FirstName, Is.EqualTo(user.FirstName + "!"));
172+
Assert.That(userDto.LastName, Is.EqualTo(user.LastName + "!"));
173+
Assert.That(userDto.Car, Is.EqualTo($"{user.Car.Name} ({user.Car.Age})"));
174+
}
175+
AssertUser(user.ConvertTo<UserDto>());
176+
AssertUser(dtoUsers.User);
177+
AssertUser(dtoUsers.Users[0]);
178+
167179
AutoMappingUtils.Reset();
168180
}
169181

tests/ServiceStack.Text.Tests/AutoMappingTests.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,15 @@ public class UserDto
6565
public class UsersData
6666
{
6767
public int Id { get; set; }
68+
69+
public User User { get; set; }
6870
public List<User> Users { get; set; }
6971
}
7072
public class UsersDto
7173
{
7274
public int Id { get; set; }
75+
76+
public UserDto User { get; set; }
7377
public List<UserDto> Users { get; set; }
7478
}
7579

0 commit comments

Comments
 (0)