Skip to content

Commit 839f1e3

Browse files
committed
Including configured enum pairs in ToEnumConverter conversion
1 parent 982edaf commit 839f1e3

File tree

10 files changed

+172
-163
lines changed

10 files changed

+172
-163
lines changed

AgileMapper/Api/Configuration/EnumPairSpecifier.cs

Lines changed: 76 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,30 @@
1313
/// </summary>
1414
/// <typeparam name="TSource">The source type being configured.</typeparam>
1515
/// <typeparam name="TTarget">The target type being configured.</typeparam>
16-
/// <typeparam name="TFirstEnum">The type of the first enum being paired.</typeparam>
17-
public class EnumPairSpecifier<TSource, TTarget, TFirstEnum>
16+
/// <typeparam name="TPairingEnum">The type of the first enum being paired.</typeparam>
17+
public class EnumPairSpecifier<TSource, TTarget, TPairingEnum>
1818
{
1919
private readonly MappingConfigInfo _configInfo;
20-
private readonly TFirstEnum[] _firstEnumMembers;
20+
private readonly TPairingEnum[] _pairingEnumMembers;
2121

2222
private EnumPairSpecifier(
2323
MappingConfigInfo configInfo,
24-
TFirstEnum[] firstEnumMembers)
24+
TPairingEnum[] pairingEnumMembers)
2525
{
2626
_configInfo = configInfo;
27-
_firstEnumMembers = firstEnumMembers;
27+
_pairingEnumMembers = pairingEnumMembers;
2828
}
2929

3030
#region Factory Method
3131

32-
internal static EnumPairSpecifier<TSource, TTarget, TFirstEnum> For(
32+
internal static EnumPairSpecifier<TSource, TTarget, TPairingEnum> For(
3333
MappingConfigInfo configInfo,
34-
params TFirstEnum[] firstEnumMembers)
34+
params TPairingEnum[] firstEnumMembers)
3535
{
36-
ThrowIfNotEnumType<TFirstEnum>();
36+
ThrowIfNotEnumType<TPairingEnum>();
3737
ThrowIfEmpty(firstEnumMembers);
3838

39-
return new EnumPairSpecifier<TSource, TTarget, TFirstEnum>(configInfo, firstEnumMembers);
39+
return new EnumPairSpecifier<TSource, TTarget, TPairingEnum>(configInfo, firstEnumMembers);
4040
}
4141

4242
private static void ThrowIfNotEnumType<T>()
@@ -48,7 +48,7 @@ private static void ThrowIfNotEnumType<T>()
4848
}
4949
}
5050

51-
private static void ThrowIfEmpty(ICollection<TFirstEnum> firstEnumMembers)
51+
private static void ThrowIfEmpty(ICollection<TPairingEnum> firstEnumMembers)
5252
{
5353
if (firstEnumMembers.None())
5454
{
@@ -61,53 +61,53 @@ private static void ThrowIfEmpty(ICollection<TFirstEnum> firstEnumMembers)
6161
private MapperContext MapperContext => _configInfo.MapperContext;
6262

6363
/// <summary>
64-
/// Configure this mapper to map the specified first enum member to the given <paramref name="secondEnumMember"/>.
64+
/// Configure this mapper to map the specified first enum member to the given <paramref name="pairedEnumMember"/>.
6565
/// </summary>
66-
/// <typeparam name="TSecondEnum">The type of the second enum being paired.</typeparam>
67-
/// <param name="secondEnumMember">The second enum member in the pair.</param>
66+
/// <typeparam name="TPairedEnum">The type of the second enum being paired.</typeparam>
67+
/// <param name="pairedEnumMember">The second enum member in the pair.</param>
6868
/// <returns>A MappingConfigContinuation with which to configure other aspects of mapping.</returns>
69-
public MappingConfigContinuation<TSource, TTarget> With<TSecondEnum>(TSecondEnum secondEnumMember)
70-
where TSecondEnum : struct
69+
public MappingConfigContinuation<TSource, TTarget> With<TPairedEnum>(TPairedEnum pairedEnumMember)
70+
where TPairedEnum : struct
7171
{
72-
return PairEnums(secondEnumMember);
72+
return PairEnums(pairedEnumMember);
7373
}
7474

7575
/// <summary>
7676
/// Configure this mapper to map the previously-specified set of enum members to the given
77-
/// <paramref name="secondEnumMembers"/>.
77+
/// <paramref name="pairedEnumMembers"/>.
7878
/// </summary>
79-
/// <typeparam name="TSecondEnum">The type of the second enum being paired.</typeparam>
80-
/// <param name="secondEnumMembers">The second set of enum members in the pairs.</param>
79+
/// <typeparam name="TPairedEnum">The type of the second enum being paired.</typeparam>
80+
/// <param name="pairedEnumMembers">The second set of enum members in the pairs.</param>
8181
/// <returns>A MappingConfigContinuation with which to configure other aspects of mapping.</returns>
82-
public MappingConfigContinuation<TSource, TTarget> With<TSecondEnum>(params TSecondEnum[] secondEnumMembers)
83-
where TSecondEnum : struct
82+
public MappingConfigContinuation<TSource, TTarget> With<TPairedEnum>(params TPairedEnum[] pairedEnumMembers)
83+
where TPairedEnum : struct
8484
{
85-
return PairEnums(secondEnumMembers);
85+
return PairEnums(pairedEnumMembers);
8686
}
8787

88-
private MappingConfigContinuation<TSource, TTarget> PairEnums<TSecondEnum>(params TSecondEnum[] secondEnumMembers)
88+
private MappingConfigContinuation<TSource, TTarget> PairEnums<TPairedEnum>(params TPairedEnum[] pairedEnumMembers)
8989
{
90-
ThrowIfNotEnumType<TSecondEnum>();
91-
ThrowIfSameTypes<TSecondEnum>();
92-
ThrowIfEmpty(secondEnumMembers);
93-
ThrowIfIncompatibleNumbers(secondEnumMembers);
90+
ThrowIfNotEnumType<TPairedEnum>();
91+
ThrowIfSameTypes<TPairedEnum>();
92+
ThrowIfEmpty(pairedEnumMembers);
93+
ThrowIfIncompatibleNumbers(pairedEnumMembers);
9494

95-
var allSecondEnumsMembersTheSame = secondEnumMembers.Length == 1;
96-
var firstSecondEnumMember = allSecondEnumsMembersTheSame ? secondEnumMembers[0] : default(TSecondEnum);
97-
var createReversePairings = _firstEnumMembers.Length == secondEnumMembers.Length;
95+
var hasSinglePairedEnumValue = pairedEnumMembers.Length == 1;
96+
var firstPairedEnumMember = hasSinglePairedEnumValue ? pairedEnumMembers[0] : default(TPairedEnum);
97+
var createReversePairings = _pairingEnumMembers.Length == pairedEnumMembers.Length;
9898

99-
for (var i = 0; i < _firstEnumMembers.Length; i++)
99+
for (var i = 0; i < _pairingEnumMembers.Length; i++)
100100
{
101-
var firstEnumMember = _firstEnumMembers[i];
102-
var secondEnumMember = allSecondEnumsMembersTheSame ? firstSecondEnumMember : secondEnumMembers[i];
101+
var pairingEnumMember = _pairingEnumMembers[i];
102+
var pairedEnumMember = hasSinglePairedEnumValue ? firstPairedEnumMember : pairedEnumMembers[i];
103103

104-
ThrowIfAlreadyPaired<TSecondEnum>(firstEnumMember);
104+
ThrowIfAlreadyPaired<TPairedEnum>(pairingEnumMember);
105105

106-
ConfigureEnumPair(firstEnumMember, secondEnumMember);
106+
ConfigureEnumPair(pairingEnumMember, pairedEnumMember);
107107

108-
if (createReversePairings)
108+
if (createReversePairings && ValueIsNotAlreadyPaired(pairedEnumMember))
109109
{
110-
ConfigureEnumPair(secondEnumMember, firstEnumMember);
110+
ConfigureEnumPair(pairedEnumMember, pairingEnumMember);
111111
}
112112
}
113113

@@ -118,54 +118,48 @@ private void ConfigureEnumPair<TPairing, TPaired>(TPairing pairingEnumMember, TP
118118
{
119119
var pairing = EnumMemberPair.For(pairingEnumMember, pairedEnumMember);
120120

121-
MapperContext.ValueConverters.Add(pairing.ValueConverter);
122121
MapperContext.UserConfigurations.Add(pairing);
123122
}
124123

125-
private static void ThrowIfSameTypes<TSecondEnum>()
124+
private static void ThrowIfSameTypes<TPairedEnum>()
126125
{
127-
if (typeof(TFirstEnum) == typeof(TSecondEnum))
126+
if (typeof(TPairingEnum) == typeof(TPairedEnum))
128127
{
129128
throw new MappingConfigurationException(
130129
"Enum pairing can only be configured between different enum types.");
131130
}
132131
}
133132

134-
private static void ThrowIfEmpty<TSecondEnum>(ICollection<TSecondEnum> secondEnumMembers)
133+
private static void ThrowIfEmpty<TPairedEnum>(ICollection<TPairedEnum> pairedEnumMembers)
135134
{
136-
if (secondEnumMembers.None())
135+
if (pairedEnumMembers.None())
137136
{
138137
throw new MappingConfigurationException("Target enum members must be provided.");
139138
}
140139
}
141140

142-
private void ThrowIfIncompatibleNumbers<TSecondEnum>(ICollection<TSecondEnum> secondEnumMembers)
141+
private void ThrowIfIncompatibleNumbers<TPairedEnum>(ICollection<TPairedEnum> pairedEnumMembers)
143142
{
144-
if (secondEnumMembers.Count != 1 &&
145-
(_firstEnumMembers.Length != secondEnumMembers.Count))
143+
if (pairedEnumMembers.Count != 1 &&
144+
(_pairingEnumMembers.Length != pairedEnumMembers.Count))
146145
{
147146
throw new MappingConfigurationException(
148-
$"If {secondEnumMembers.Count} paired enum values are provided, " +
149-
$"{secondEnumMembers.Count} pairing enum values are required.");
147+
$"If {pairedEnumMembers.Count} paired enum values are provided, " +
148+
$"{pairedEnumMembers.Count} pairing enum values are required.");
150149
}
151150
}
152151

153-
private void ThrowIfAlreadyPaired<TSecondEnum>(TFirstEnum firstEnumMember)
152+
private void ThrowIfAlreadyPaired<TPairedEnum>(TPairingEnum pairingEnumValue)
154153
{
155-
var relevantPairings = MapperContext
156-
.UserConfigurations
157-
.GetEnumPairingsFor(typeof(TFirstEnum), typeof(TSecondEnum))
158-
.ToArray();
159-
160-
if (relevantPairings.None())
154+
if (!TryGetRelevantPairings<TPairingEnum, TPairedEnum>(out var relevantPairings))
161155
{
162156
return;
163157
}
164158

165-
var firstEnumMemberName = firstEnumMember.ToString();
159+
var pairingEnumValueName = pairingEnumValue.ToString();
166160

167161
var confictingPairing = relevantPairings
168-
.FirstOrDefault(ep => ep.FirstEnumMemberName == firstEnumMemberName);
162+
.FirstOrDefault(ep => ep.PairingEnumMemberName == pairingEnumValueName);
169163

170164
if (confictingPairing == null)
171165
{
@@ -175,10 +169,32 @@ private void ThrowIfAlreadyPaired<TSecondEnum>(TFirstEnum firstEnumMember)
175169
throw new MappingConfigurationException(string.Format(
176170
CultureInfo.InvariantCulture,
177171
"{0}.{1} is already paired with {2}.{3}",
178-
typeof(TFirstEnum).Name,
179-
firstEnumMemberName,
180-
typeof(TSecondEnum).Name,
181-
confictingPairing.SecondEnumMemberName));
172+
typeof(TPairingEnum).Name,
173+
pairingEnumValueName,
174+
typeof(TPairedEnum).Name,
175+
confictingPairing.PairedEnumMemberName));
176+
}
177+
178+
private bool TryGetRelevantPairings<TPairing, TPaired>(out EnumMemberPair[] relevantPairings)
179+
{
180+
relevantPairings = MapperContext
181+
.UserConfigurations
182+
.GetEnumPairingsFor(typeof(TPairing), typeof(TPaired))
183+
.ToArray();
184+
185+
return relevantPairings.Any();
186+
}
187+
188+
private bool ValueIsNotAlreadyPaired<TPairedEnum>(TPairedEnum pairedEnumValue)
189+
{
190+
if (!TryGetRelevantPairings<TPairedEnum, TPairingEnum>(out var relevantPairings))
191+
{
192+
return true;
193+
}
194+
195+
var pairedEnumMemberName = pairedEnumValue.ToString();
196+
197+
return relevantPairings.None(pair => pair.PairingEnumMemberName == pairedEnumMemberName);
182198
}
183199
}
184200
}
Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,44 @@
11
namespace AgileObjects.AgileMapper.Configuration
22
{
33
using System;
4-
using System.Linq.Expressions;
54
using Extensions.Internal;
6-
using TypeConversion;
75

86
internal class EnumMemberPair
97
{
10-
private readonly Type _firstEnumType;
11-
private readonly Type _secondEnumType;
12-
13-
public EnumMemberPair(
14-
Type firstEnumType,
15-
string firstEnumMemberName,
16-
Type secondEnumType,
17-
string secondEnumMemberName,
18-
IValueConverter valueConverter)
8+
private readonly Type _pairingEnumType;
9+
private readonly Type _pairedEnumType;
10+
11+
private EnumMemberPair(
12+
Type pairingEnumType,
13+
string pairingEnumMemberName,
14+
Type pairedEnumType,
15+
string pairedEnumMemberName)
1916
{
20-
FirstEnumMemberName = firstEnumMemberName;
21-
SecondEnumMemberName = secondEnumMemberName;
22-
ValueConverter = valueConverter;
23-
_firstEnumType = firstEnumType;
24-
_secondEnumType = secondEnumType;
17+
PairingEnumMemberName = pairingEnumMemberName;
18+
PairedEnumMemberName = pairedEnumMemberName;
19+
_pairingEnumType = pairingEnumType;
20+
_pairedEnumType = pairedEnumType;
2521
}
2622

2723
public static EnumMemberPair For<TFirstEnum, TSecondEnum>(
28-
TFirstEnum firstEnumMember,
29-
TSecondEnum secondEnumMember)
24+
TFirstEnum pairingEnumMember,
25+
TSecondEnum pairedEnumMember)
3026
{
31-
var firstValue = firstEnumMember.ToConstantExpression();
32-
var secondValue = secondEnumMember.ToConstantExpression();
33-
34-
var valueConverter = new ConfiguredValueConverter(
35-
firstValue.Type,
36-
secondValue,
37-
(sourceValue, targetType) => Expression.Equal(sourceValue, firstValue));
27+
var pairingValue = pairingEnumMember.ToConstantExpression();
28+
var pairedValue = pairedEnumMember.ToConstantExpression();
3829

3930
return new EnumMemberPair(
40-
firstValue.Type,
41-
firstEnumMember.ToString(),
42-
secondValue.Type,
43-
secondEnumMember.ToString(),
44-
valueConverter);
31+
pairingValue.Type,
32+
pairingEnumMember.ToString(),
33+
pairedValue.Type,
34+
pairedEnumMember.ToString());
4535
}
4636

47-
public string FirstEnumMemberName { get; }
48-
49-
public string SecondEnumMemberName { get; }
37+
public string PairingEnumMemberName { get; }
5038

51-
public IValueConverter ValueConverter { get; }
39+
public string PairedEnumMemberName { get; }
5240

5341
public bool IsFor(Type sourceEnumType, Type targetEnumType)
54-
=> (_firstEnumType == sourceEnumType) && (_secondEnumType == targetEnumType);
42+
=> (_pairingEnumType == sourceEnumType) && (_pairedEnumType == targetEnumType);
5543
}
5644
}

AgileMapper/Configuration/UserConfigurationSet.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ private List<EnumMemberPair> EnumPairings
152152

153153
public void Add(EnumMemberPair enumPairing) => EnumPairings.Add(enumPairing);
154154

155-
public IEnumerable<EnumMemberPair> GetEnumPairingsFor(Type sourceType, Type targetType)
156-
=> _enumPairings?.Where(ep => ep.IsFor(sourceType, targetType)) ?? Enumerable<EnumMemberPair>.Empty;
155+
public IEnumerable<EnumMemberPair> GetEnumPairingsFor(Type sourceEnumType, Type targetEnumType)
156+
=> _enumPairings?.Where(ep => ep.IsFor(sourceEnumType, targetEnumType)) ?? Enumerable<EnumMemberPair>.Empty;
157157

158158
#endregion
159159

AgileMapper/MapperContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public MapperContext()
2626
ObjectMapperFactory = new ObjectMapperFactory(Cache);
2727
UserConfigurations = new UserConfigurationSet(this);
2828
ConstructionFactory = new ComplexTypeConstructionFactory(Cache);
29-
ValueConverters = new ConverterSet();
29+
ValueConverters = new ConverterSet(UserConfigurations);
3030
RuleSets = new MappingRuleSetCollection();
3131
}
3232

AgileMapper/TypeConversion/ConfiguredValueConverter.cs

Lines changed: 0 additions & 26 deletions
This file was deleted.

AgileMapper/TypeConversion/ConverterSet.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ internal class ConverterSet
1313
{
1414
private readonly List<IValueConverter> _converters;
1515

16-
public ConverterSet()
16+
public ConverterSet(UserConfigurationSet userConfigurations)
1717
{
1818
var toStringConverter = new ToStringConverter();
1919

@@ -22,7 +22,7 @@ public ConverterSet()
2222
toStringConverter,
2323
new ToNumericConverter<int>(toStringConverter),
2424
new ToBoolConverter(toStringConverter),
25-
new ToEnumConverter(toStringConverter),
25+
new ToEnumConverter(toStringConverter, userConfigurations),
2626
new TryParseConverter<DateTime>(toStringConverter),
2727
new TryParseConverter<Guid>(toStringConverter),
2828
new ToNumericConverter<decimal>(toStringConverter),
@@ -91,8 +91,7 @@ public Expression GetConversion(Expression sourceValue, Type targetType)
9191

9292
var conversion = converters.ReverseChain(
9393
converter => converter.GetConversion(sourceValue, targetType),
94-
(conversionSoFar, converter) =>
95-
converter.GetConversionOption(sourceValue, targetType, conversionSoFar));
94+
(conversionSoFar, converter) => converter.GetConversionOption(sourceValue, conversionSoFar));
9695

9796
return conversion;
9897
}

0 commit comments

Comments
 (0)