Skip to content

Commit 6beb151

Browse files
committed
Skipping pre- and post-object-creation callbacks when the target object is definitely already populated
1 parent 69fea44 commit 6beb151

File tree

4 files changed

+80
-24
lines changed

4 files changed

+80
-24
lines changed

AgileMapper.UnitTests/WhenViewingMappingPlans.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,27 @@ public void ShouldNotRangeCheckNullableToNonNullableValues()
266266
plan.ShouldNotContain("Value.HasValue");
267267
}
268268

269+
[Fact]
270+
public void ShouldNotAttemptUnnecessaryObjectCreationCallbacks()
271+
{
272+
using (var mapper = Mapper.CreateNew())
273+
{
274+
mapper.WhenMapping
275+
.Over<PublicField<string>>()
276+
.Before
277+
.CreatingInstances
278+
.Call(ctx => Console.WriteLine("Nope!"))
279+
.And
280+
.After
281+
.CreatingInstances
282+
.Call(ctx => Console.WriteLine("No way!"));
283+
284+
string plan = mapper.GetPlanFor<PublicField<string>>().Over<PublicField<string>>();
285+
286+
plan.ShouldNotContain("Invoke");
287+
}
288+
}
289+
269290
[Fact]
270291
public void ShouldShowEnumMismatches()
271292
{

AgileMapper/Api/Configuration/IPreInstanceCreationCallbackSpecifier.cs

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,40 @@
99
/// </summary>
1010
/// <typeparam name="TSource">The source type to which the configuration should apply.</typeparam>
1111
/// <typeparam name="TTarget">The target type to which the configuration should apply.</typeparam>
12-
public interface IPreInstanceCreationCallbackSpecifier<out TSource, out TTarget>
12+
public interface IPreInstanceCreationCallbackSpecifier<TSource, TTarget>
1313
{
14-
/// <summary>
15-
/// Configure a callback to call in the configured conditions. The callback is passed a context
16-
/// object containing the current mapping's source and target objects.
17-
/// </summary>
14+
/// <summary>
15+
/// Configure a callback to call in the configured conditions. The callback is passed a context
16+
/// object containing the current mapping's source and target objects.
17+
/// </summary>
1818
/// <param name="callback">The callback to call.</param>
19-
void Call(Action<IMappingData<TSource, TTarget>> callback);
19+
/// <returns>
20+
/// A MappingConfigContinuation to enable further configuration of mappings from and to the source and
21+
/// target type being configured.
22+
/// </returns>
23+
/// <returns></returns>
24+
MappingConfigContinuation<TSource, TTarget> Call(Action<IMappingData<TSource, TTarget>> callback);
2025

21-
/// <summary>
22-
/// Configure a callback to call in the configured conditions. The callback is passed the current
23-
/// mapping's source and target objects.
24-
/// </summary>
26+
/// <summary>
27+
/// Configure a callback to call in the configured conditions. The callback is passed the current
28+
/// mapping's source and target objects.
29+
/// </summary>
2530
/// <param name="callback">The callback to call.</param>
26-
void Call(Action<TSource, TTarget> callback);
31+
/// <returns>
32+
/// A MappingConfigContinuation to enable further configuration of mappings from and to the source and
33+
/// target type being configured.
34+
/// </returns>
35+
MappingConfigContinuation<TSource, TTarget> Call(Action<TSource, TTarget> callback);
2736

28-
/// <summary>
29-
/// Configure a callback to call in the configured conditions. The callback is passed the current
30-
/// mapping's source and target objects and the current enumerable index, if applicable.
31-
/// </summary>
37+
/// <summary>
38+
/// Configure a callback to call in the configured conditions. The callback is passed the current
39+
/// mapping's source and target objects and the current enumerable index, if applicable.
40+
/// </summary>
3241
/// <param name="callback">The callback to call.</param>
33-
void Call(Action<TSource, TTarget, int?> callback);
42+
/// <returns>
43+
/// A MappingConfigContinuation to enable further configuration of mappings from and to the source and
44+
/// target type being configured.
45+
/// </returns>
46+
MappingConfigContinuation<TSource, TTarget> Call(Action<TSource, TTarget, int?> callback);
3447
}
3548
}

AgileMapper/Api/Configuration/InstanceCreationCallbackSpecifier.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,23 @@ private InstanceCreationCallbackSpecifier<TSource, TTarget, TObject> SetConditio
4545
return this;
4646
}
4747

48-
void IPreInstanceCreationCallbackSpecifier<TSource, TTarget>.Call(
48+
MappingConfigContinuation<TSource, TTarget> IPreInstanceCreationCallbackSpecifier<TSource, TTarget>.Call(
4949
Action<IMappingData<TSource, TTarget>> callback)
50-
=> CreateCallbackFactory(callback);
50+
{
51+
return CreateCallbackFactory(callback);
52+
}
5153

52-
void IPreInstanceCreationCallbackSpecifier<TSource, TTarget>.Call(
54+
MappingConfigContinuation<TSource, TTarget> IPreInstanceCreationCallbackSpecifier<TSource, TTarget>.Call(
5355
Action<TSource, TTarget> callback)
54-
=> CreateCallbackFactory(callback);
56+
{
57+
return CreateCallbackFactory(callback);
58+
}
5559

56-
void IPreInstanceCreationCallbackSpecifier<TSource, TTarget>.Call(
60+
MappingConfigContinuation<TSource, TTarget> IPreInstanceCreationCallbackSpecifier<TSource, TTarget>.Call(
5761
Action<TSource, TTarget, int?> callback)
58-
=> CreateCallbackFactory(callback);
62+
{
63+
return CreateCallbackFactory(callback);
64+
}
5965

6066
#endregion
6167

AgileMapper/ObjectPopulation/ComplexTypes/PopulationExpressionFactoryBase.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ internal abstract class PopulationExpressionFactoryBase
1414
public IEnumerable<Expression> GetPopulation(IObjectMappingData mappingData)
1515
{
1616
var mapperData = mappingData.MapperData;
17-
var preCreationCallback = GetCreationCallbackOrNull(Before, mapperData);
18-
var postCreationCallback = GetCreationCallbackOrNull(After, mapperData);
17+
18+
GetCreationCallbacks(mapperData, out var preCreationCallback, out var postCreationCallback);
19+
1920
var populationsAndCallbacks = GetPopulationsAndCallbacks(mappingData).ToList();
2021

2122
yield return preCreationCallback;
@@ -39,6 +40,21 @@ public IEnumerable<Expression> GetPopulation(IObjectMappingData mappingData)
3940
mappingData.MapperKey.AddSourceMemberTypeTesterIfRequired(mappingData);
4041
}
4142

43+
private static void GetCreationCallbacks(
44+
IMemberMapperData mapperData,
45+
out Expression preCreationCallback,
46+
out Expression postCreationCallback)
47+
{
48+
if (mapperData.TargetIsDefinitelyPopulated())
49+
{
50+
preCreationCallback = postCreationCallback = null;
51+
return;
52+
}
53+
54+
preCreationCallback = GetCreationCallbackOrNull(Before, mapperData);
55+
postCreationCallback = GetCreationCallbackOrNull(After, mapperData);
56+
}
57+
4258
private static Expression GetCreationCallbackOrNull(CallbackPosition callbackPosition, IMemberMapperData mapperData)
4359
=> mapperData.MapperContext.UserConfigurations.GetCreationCallbackOrNull(callbackPosition, mapperData);
4460

0 commit comments

Comments
 (0)