Permalink
Browse files

Source members can be ignored for source-level configuration validation

  • Loading branch information...
jbogard committed Dec 8, 2011
1 parent f8c40ad commit 0a46077a143955043735918425e02e88260e7e1b
@@ -326,6 +326,9 @@
<Compile Include="..\AutoMapper\ResolutionResult.cs">
<Link>ResolutionResult.cs</Link>
</Compile>
+ <Compile Include="..\AutoMapper\SourceMemberConfig.cs">
+ <Link>SourceMemberConfig.cs</Link>
+ </Compile>
<Compile Include="..\AutoMapper\ThreadSafeList.cs">
<Link>ThreadSafeList.cs</Link>
</Compile>
@@ -169,6 +169,7 @@
<Compile Include="ResolutionContext.cs" />
<Compile Include="Internal\ResolutionExpression.cs" />
<Compile Include="ResolutionResult.cs" />
+ <Compile Include="SourceMemberConfig.cs" />
<Compile Include="ThreadSafeList.cs" />
<Compile Include="TypeInfo.cs" />
<Compile Include="TypeMap.cs" />
@@ -32,6 +32,7 @@ public interface IMappingExpression<TSource, TDestination>
IMappingExpression<TSource, TDestination> MaxDepth(int depth);
IMappingExpression<TSource, TDestination> ConstructUsingServiceLocator();
IMappingExpression<TDestination, TSource> ReverseMap();
+ IMappingExpression<TSource, TDestination> ForSourceMember(Expression<Func<TSource, object>> sourceMember, Action<ISourceMemberConfigurationExpression<TSource>> memberOptions);
}
public interface IMemberConfigurationExpression
@@ -43,6 +44,11 @@ public interface IMemberConfigurationExpression
void Ignore();
}
+ public interface ISourceMemberConfigurationExpression<TSource>
+ {
+ void Ignore();
+ }
+
public interface IMemberConfigurationExpression<TSource>
{
void SkipFormatter<TValueFormatter>() where TValueFormatter : IValueFormatter;
@@ -262,6 +262,15 @@ public void Condition(Func<TSource, bool> condition)
return _configurationContainer.CreateMap<TDestination, TSource>();
}
+ public IMappingExpression<TSource, TDestination> ForSourceMember(Expression<Func<TSource, object>> sourceMember, Action<ISourceMemberConfigurationExpression<TSource>> memberOptions)
+ {
+ var srcConfig = new SourceMappingExpression(_typeMap, sourceMember);
+
+ memberOptions(srcConfig);
+
+ return this;
+ }
+
private static bool PassesDepthCheck(ResolutionContext context, int maxDepth)
{
if (context.InstanceCache.ContainsKey(context))
@@ -401,6 +410,23 @@ public void As<T>()
return (TServiceType)_serviceCtor(type);
};
}
+
+ private class SourceMappingExpression : ISourceMemberConfigurationExpression<TSource>
+ {
+ private readonly SourceMemberConfig _sourcePropertyConfig;
+
+ public SourceMappingExpression(TypeMap typeMap, LambdaExpression sourceMember)
+ {
+ var memberInfo = ReflectionHelper.FindProperty(sourceMember);
+
+ _sourcePropertyConfig = typeMap.FindOrCreateSourceMemberConfigFor(memberInfo);
+ }
+
+ public void Ignore()
+ {
+ _sourcePropertyConfig.Ignore();
+ }
+ }
}
}
@@ -0,0 +1,27 @@
+using System;
+using System.Reflection;
+
+namespace AutoMapper
+{
+ public class SourceMemberConfig
+ {
+ private bool _ignored;
+
+ public SourceMemberConfig(MemberInfo sourceMember)
+ {
+ SourceMember = sourceMember;
+ }
+
+ public MemberInfo SourceMember { get; private set; }
+
+ public void Ignore()
+ {
+ _ignored = true;
+ }
+
+ public bool IsIgnored()
+ {
+ return _ignored;
+ }
+ }
+}
View
@@ -13,6 +13,7 @@ public class TypeMap
private readonly TypeInfo _destinationType;
private readonly IDictionary<Type, Type> _includedDerivedTypes = new Dictionary<Type, Type>();
private readonly ThreadSafeList<PropertyMap> _propertyMaps = new ThreadSafeList<PropertyMap>();
+ private readonly ThreadSafeList<SourceMemberConfig> _sourceMemberConfigs = new ThreadSafeList<SourceMemberConfig>();
private readonly IList<PropertyMap> _inheritedMaps = new List<PropertyMap>();
private PropertyMap[] _orderedPropertyMaps;
private readonly TypeInfo _sourceType;
@@ -133,11 +134,16 @@ public string[] GetUnmappedPropertyNames()
.Where(pm => pm.CustomExpression != null)
.Select(pm => pm.SourceMember.Name);
+ var ignoredSourceMembers = _sourceMemberConfigs
+ .Where(smc => smc.IsIgnored())
+ .Select(pm => pm.SourceMember.Name);
+
properties = _sourceType.GetPublicReadAccessors()
.Select(p => p.Name)
.Except(autoMappedProperties)
.Except(inheritedProperties)
.Except(redirectedSourceMembers)
+ .Except(ignoredSourceMembers)
;
}
@@ -274,5 +280,17 @@ public void AddConstructorMap(ConstructorInfo constructorInfo, IEnumerable<Const
var ctorMap = new ConstructorMap(constructorInfo, parameters);
_constructorMap = ctorMap;
}
+
+ public SourceMemberConfig FindOrCreateSourceMemberConfigFor(MemberInfo sourceMember)
+ {
+ var config = _sourceMemberConfigs.FirstOrDefault(smc => smc.SourceMember == sourceMember);
+ if (config == null)
+ {
+ config = new SourceMemberConfig(sourceMember);
+ _sourceMemberConfigs.Add(config);
+ }
+
+ return config;
+ }
}
}
@@ -135,5 +135,35 @@ public void Should_not_throw_a_configuration_validation_error()
}
}
+ public class When_validating_only_against_source_members_and_unmatching_source_members_are_manually_mapped_with_resolvers : NonValidatingSpecBase
+ {
+ public class Source
+ {
+ public int Value { get; set; }
+ public int Value2 { get; set; }
+ }
+ public class Destination
+ {
+ public int Value { get; set; }
+ public int Value3 { get; set; }
+ }
+
+ protected override void Establish_context()
+ {
+ Mapper.Initialize(cfg =>
+ {
+ cfg.CreateMap<Source, Destination>(MemberList.Source)
+ .ForMember(dest => dest.Value3, opt => opt.ResolveUsing(src => src.Value2))
+ .ForSourceMember(src => src.Value2, opt => opt.Ignore());
+ });
+ }
+
+ [Test]
+ public void Should_not_throw_a_configuration_validation_error()
+ {
+ typeof(AutoMapperConfigurationException).ShouldNotBeThrownBy(Mapper.AssertConfigurationIsValid);
+ }
+ }
+
}
}

0 comments on commit 0a46077

Please sign in to comment.