コード例 #1
0
ファイル: ClassMap.cs プロジェクト: kendallb/CsvHelper
        /// <summary>
        /// Applies attribute configurations to the map.
        /// </summary>
        /// <param name="referenceMap">The reference map.</param>
        protected virtual void ApplyAttributes(MemberReferenceMap referenceMap)
        {
            var member = referenceMap.Data.Member;

            if (member.GetCustomAttribute(typeof(HeaderPrefixAttribute)) is HeaderPrefixAttribute headerPrefixAttribute)
            {
                referenceMap.Data.Prefix = headerPrefixAttribute.Prefix ?? member.Name + ".";
            }
        }
コード例 #2
0
        /// <summary>
        /// Applies attribute configurations to the map.
        /// </summary>
        /// <param name="referenceMap">The reference map.</param>
        protected virtual void ApplyAttributes(MemberReferenceMap referenceMap)
        {
            var member     = referenceMap.Data.Member;
            var attributes = member.GetCustomAttributes().OfType <IMemberReferenceMapper>();

            foreach (var attribute in attributes)
            {
                attribute.ApplyTo(referenceMap);
            }
        }
コード例 #3
0
        /// <summary>
        /// Applies attribute configurations to the map.
        /// </summary>
        /// <param name="referenceMap">The reference map.</param>
        protected virtual void ApplyAttributes(MemberReferenceMap referenceMap)
        {
            var member = referenceMap.Data.Member;

            //if( member.GetCustomAttribute( typeof( HeaderPrefixAttribute ) ) is HeaderPrefixAttribute headerPrefixAttribute )
            HeaderPrefixAttribute headerPrefixAttribute = member.GetCustomAttributes(typeof(HeaderPrefixAttribute), false).FirstOrDefault() as HeaderPrefixAttribute;

            if (headerPrefixAttribute != null)
            {
                referenceMap.Data.Prefix = headerPrefixAttribute.Prefix ?? member.Name + ".";
            }
        }
コード例 #4
0
        /// <summary>
        /// Maps a member to another class map.
        /// </summary>
        /// <param name="classMapType">The type of the class map.</param>
        /// <param name="member">The member.</param>
        /// <param name="constructorArgs">Constructor arguments used to create the reference map.</param>
        /// <returns>The reference mapping for the member.</returns>
        public virtual MemberReferenceMap References(Type classMapType, MemberInfo member, params object[] constructorArgs)
        {
            if (!typeof(ClassMap).IsAssignableFrom(classMapType))
            {
                throw new InvalidOperationException($"Argument {nameof(classMapType)} is not a CsvClassMap.");
            }

            var existingMap = ReferenceMaps.Find(member);

            if (existingMap != null)
            {
                return(existingMap);
            }

            var map = (ClassMap)ReflectionHelper.CreateInstance(classMapType, constructorArgs);

            map.ReIndex(GetMaxIndex() + 1);
            var reference = new MemberReferenceMap(member, map);

            ReferenceMaps.Add(reference);

            return(reference);
        }
コード例 #5
0
        /// <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="configuration">The configuration.</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, CsvConfiguration configuration, LinkedList <Type> mapParents, int indexStart = 0)
        {
            var type = map.GetGenericType();

            var flags = BindingFlags.Instance | BindingFlags.Public;

            if (configuration.IncludePrivateMembers)
            {
                flags = flags | BindingFlags.NonPublic;
            }

            var members = new List <MemberInfo>();

            if ((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 ((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)
            {
                var typeConverterType = configuration.TypeConverterCache.GetConverter(member).GetType();

                if (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 (configuration.IgnoreReferences)
                    {
                        continue;
                    }

                    if (CheckForCircularReference(member.MemberType(), mapParents))
                    {
                        continue;
                    }

                    mapParents.AddLast(type);
                    var refMapType = typeof(DefaultClassMap <>).MakeGenericType(member.MemberType());
                    var refMap     = (ClassMap)ReflectionHelper.CreateInstance(refMapType);

                    if (memberTypeInfo.HasConstructor() && !memberTypeInfo.HasParameterlessConstructor() && !memberTypeInfo.IsUserDefinedStruct())
                    {
                        AutoMapConstructorParameters(refMap, configuration, mapParents, Math.Max(map.GetMaxIndex() + 1, indexStart));
                    }

                    // Need to use Max here for nested types.
                    AutoMapMembers(refMap, configuration, 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 (configuration.ReferenceHeaderPrefix != null)
                        {
                            referenceMap.Data.Prefix = 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(), configuration.TypeConverterOptionsCache.GetOptions(member.MemberType()), memberMap.Data.TypeConverterOptions);
                    memberMap.Data.Index = map.GetMaxIndex() + 1;

                    ApplyAttributes(memberMap);

                    map.MemberMaps.Add(memberMap);
                }
            }

            map.ReIndex(indexStart);
        }
コード例 #6
0
        /// <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="configuration">The configuration.</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, Configuration configuration, LinkedList <Type> mapParents, int indexStart = 0)
        {
            var type = map.GetGenericType();

            var flags = BindingFlags.Instance | BindingFlags.Public;

            if (configuration.IncludePrivateMembers)
            {
                flags = flags | BindingFlags.NonPublic;
            }

            var members = new List <MemberInfo>();

            if ((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 type.GetProperties(flags))
                {
                    properties.Add(ReflectionHelper.GetDeclaringProperty(type, property, flags));
                }

                members.AddRange(properties);
            }

            if ((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)
            {
                var typeConverterType = configuration.TypeConverterFactory.GetConverter(member.MemberType()).GetType();

                if (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 && (memberTypeInfo.HasParameterlessConstructor() || memberTypeInfo.IsUserDefinedStruct()))
                {
                    // If the type is not one covered by our type converters
                    // and it has a parameterless constructor, create a
                    // reference map for it.

                    if (configuration.IgnoreReferences)
                    {
                        continue;
                    }

                    if (CheckForCircularReference(member.MemberType(), mapParents))
                    {
                        continue;
                    }

                    mapParents.AddLast(type);
                    var refMapType = typeof(DefaultClassMap <>).MakeGenericType(member.MemberType());
                    var refMap     = (ClassMap)ReflectionHelper.CreateInstance(refMapType);
                    // Need to use Max here for nested types.
                    AutoMapMembers(refMap, configuration, 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 (configuration.PrefixReferenceHeaders)
                        {
                            referenceMap.Prefix();
                        }

                        map.ReferenceMaps.Add(referenceMap);
                    }
                }
                else
                {
                    var memberMap = MemberMap.CreateGeneric(map.ClassType, member);
                    // Use global values as the starting point.
                    memberMap.Data.TypeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions(), configuration.TypeConverterOptionsFactory.GetOptions(member.MemberType()), memberMap.Data.TypeConverterOptions);
                    memberMap.Data.Index = map.GetMaxIndex() + 1;
                    if (!isDefaultConverter)
                    {
                        // 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.
                        map.MemberMaps.Add(memberMap);
                    }
                }
            }

            map.ReIndex(indexStart);
        }