/// <summary> /// Auto maps the given map and checks for circular references as it goes. /// </summary> /// <param name="map">The map to auto map.</param> /// <param name="context">The context.</param> /// <param name="mapParents">The list of parents for the map.</param> /// <param name="indexStart">The index starting point.</param> protected virtual void AutoMapMembers(ClassMap map, CsvContext context, LinkedList <Type> mapParents, int indexStart = 0) { var type = map.GetGenericType(); var flags = BindingFlags.Instance | BindingFlags.Public; if (context.Configuration.IncludePrivateMembers) { flags = flags | BindingFlags.NonPublic; } var members = new List <MemberInfo>(); if ((context.Configuration.MemberTypes & MemberTypes.Properties) == MemberTypes.Properties) { // We need to go up the declaration tree and find the actual type the property // exists on and use that PropertyInfo instead. This is so we can get the private // set method for the property. var properties = new List <PropertyInfo>(); foreach (var property in ReflectionHelper.GetUniqueProperties(type, flags)) { if (properties.Any(p => p.Name == property.Name)) { // Multiple properties could have the same name if a child class property // is hiding a parent class property by using `new`. It's possible that // the order of the properties returned continue; } properties.Add(ReflectionHelper.GetDeclaringProperty(type, property, flags)); } members.AddRange(properties); } if ((context.Configuration.MemberTypes & MemberTypes.Fields) == MemberTypes.Fields) { var fields = new List <MemberInfo>(); foreach (var field in type.GetFields(flags)) { if (!field.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any()) { fields.Add(field); } } members.AddRange(fields); } foreach (var member in members) { if (member.GetCustomAttribute <IgnoreAttribute>() != null) { // Ignore this member including its tree if it's a reference. continue; } var typeConverterType = context.TypeConverterCache.GetConverter(member).GetType(); if (context.Configuration.HasHeaderRecord && enumerableConverters.Contains(typeConverterType)) { // Enumerable converters can't write the header properly, so skip it. continue; } var memberTypeInfo = member.MemberType().GetTypeInfo(); var isDefaultConverter = typeConverterType == typeof(DefaultTypeConverter); if (isDefaultConverter) { // If the type is not one covered by our type converters // and it has a parameterless constructor, create a // reference map for it. if (context.Configuration.IgnoreReferences) { continue; } if (CheckForCircularReference(member.MemberType(), mapParents)) { continue; } mapParents.AddLast(type); var refMapType = typeof(DefaultClassMap <>).MakeGenericType(member.MemberType()); var refMap = (ClassMap)ObjectResolver.Current.Resolve(refMapType); if (memberTypeInfo.HasConstructor() && !memberTypeInfo.HasParameterlessConstructor() && !memberTypeInfo.IsUserDefinedStruct()) { AutoMapConstructorParameters(refMap, context, mapParents, Math.Max(map.GetMaxIndex() + 1, indexStart)); } // Need to use Max here for nested types. AutoMapMembers(refMap, context, mapParents, Math.Max(map.GetMaxIndex() + 1, indexStart)); mapParents.Drop(mapParents.Find(type)); if (refMap.MemberMaps.Count > 0 || refMap.ReferenceMaps.Count > 0) { var referenceMap = new MemberReferenceMap(member, refMap); if (context.Configuration.ReferenceHeaderPrefix != null) { referenceMap.Data.Prefix = context.Configuration.ReferenceHeaderPrefix(member.MemberType(), member.Name); } ApplyAttributes(referenceMap); map.ReferenceMaps.Add(referenceMap); } } else { // Only add the member map if it can be converted later on. // If the member will use the default converter, don't add it because // we don't want the .ToString() value to be used when auto mapping. // Use the top of the map tree. This will maps that have been auto mapped // to later on get a reference to a map by doing map.Map( m => m.A.B.C.Id ) // and it will return the correct parent map type of A instead of C. var classType = mapParents.First?.Value ?? map.ClassType; var memberMap = MemberMap.CreateGeneric(classType, member); // Use global values as the starting point. memberMap.Data.TypeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions(), context.TypeConverterOptionsCache.GetOptions(member.MemberType()), memberMap.Data.TypeConverterOptions); memberMap.Data.Index = map.GetMaxIndex() + 1; ApplyAttributes(memberMap); map.MemberMaps.Add(memberMap); } } map.ReIndex(indexStart); }
public MemberMapBuilder(ClassMap <TClass> classMap, MemberMap <TClass, TMember> memberMap) { this.classMap = classMap; this.memberMap = memberMap; }
/// <summary> /// Applies attribute configurations to the map. /// </summary> /// <param name="memberMap">The member map.</param> protected virtual void ApplyAttributes(MemberMap memberMap) { var member = memberMap.Data.Member; if (member.GetCustomAttribute(typeof(IndexAttribute)) is IndexAttribute indexAttribute) { memberMap.Data.Index = indexAttribute.Index; memberMap.Data.IndexEnd = indexAttribute.IndexEnd; memberMap.Data.IsIndexSet = true; } if (member.GetCustomAttribute(typeof(NameAttribute)) is NameAttribute nameAttribute) { memberMap.Data.Names.Clear(); memberMap.Data.Names.AddRange(nameAttribute.Names); memberMap.Data.IsNameSet = true; } if (member.GetCustomAttribute(typeof(NameIndexAttribute)) is NameIndexAttribute nameIndexAttribute) { memberMap.Data.NameIndex = nameIndexAttribute.NameIndex; } if (member.GetCustomAttribute(typeof(IgnoreAttribute)) is IgnoreAttribute ignoreAttribute) { memberMap.Data.Ignore = true; } if (member.GetCustomAttribute(typeof(OptionalAttribute)) is OptionalAttribute optionalAttribute) { memberMap.Data.IsOptional = true; } if (member.GetCustomAttribute(typeof(DefaultAttribute)) is DefaultAttribute defaultAttribute) { memberMap.Data.Default = defaultAttribute.Default; memberMap.Data.IsDefaultSet = true; } if (member.GetCustomAttribute(typeof(ConstantAttribute)) is ConstantAttribute constantAttribute) { memberMap.Data.Constant = constantAttribute.Constant; memberMap.Data.IsConstantSet = true; } if (member.GetCustomAttribute(typeof(TypeConverterAttribute)) is TypeConverterAttribute typeConverterAttribute) { memberMap.Data.TypeConverter = typeConverterAttribute.TypeConverter; } if (member.GetCustomAttribute(typeof(CultureInfoAttribute)) is CultureInfoAttribute cultureInfoAttribute) { memberMap.Data.TypeConverterOptions.CultureInfo = cultureInfoAttribute.CultureInfo; } if (member.GetCustomAttribute(typeof(DateTimeStylesAttribute)) is DateTimeStylesAttribute dateTimeStylesAttribute) { memberMap.Data.TypeConverterOptions.DateTimeStyle = dateTimeStylesAttribute.DateTimeStyles; } if (member.GetCustomAttribute(typeof(NumberStylesAttribute)) is NumberStylesAttribute numberStylesAttribute) { memberMap.Data.TypeConverterOptions.NumberStyle = numberStylesAttribute.NumberStyles; } if (member.GetCustomAttribute(typeof(FormatAttribute)) is FormatAttribute formatAttribute) { memberMap.Data.TypeConverterOptions.Formats = formatAttribute.Formats; } if (member.GetCustomAttribute(typeof(BooleanTrueValuesAttribute)) is BooleanTrueValuesAttribute booleanTrueValuesAttribute) { memberMap.Data.TypeConverterOptions.BooleanTrueValues.Clear(); memberMap.Data.TypeConverterOptions.BooleanTrueValues.AddRange(booleanTrueValuesAttribute.TrueValues); } if (member.GetCustomAttribute(typeof(BooleanFalseValuesAttribute)) is BooleanFalseValuesAttribute booleanFalseValuesAttribute) { memberMap.Data.TypeConverterOptions.BooleanFalseValues.Clear(); memberMap.Data.TypeConverterOptions.BooleanFalseValues.AddRange(booleanFalseValuesAttribute.FalseValues); } if (member.GetCustomAttribute(typeof(NullValuesAttribute)) is NullValuesAttribute nullValuesAttribute) { memberMap.Data.TypeConverterOptions.NullValues.Clear(); memberMap.Data.TypeConverterOptions.NullValues.AddRange(nullValuesAttribute.NullValues); } }
/// <summary> /// Creates a new instance using the given <see cref="MemberMap"/>. /// </summary> /// <param name="memberMap">The member map the options are being applied to.</param> public MapTypeConverterOption(MemberMap memberMap) { this.memberMap = memberMap; }