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

            foreach (var attribute in attributes)
            {
                attribute.ApplyTo(referenceMap);
            }
        }
コード例 #2
0
        /// <summary>
        /// Auto maps the given map using constructor parameters.
        /// </summary>
        /// <param name="map">The 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 AutoMapConstructorParameters(ClassMap map, CsvConfiguration configuration, LinkedList <Type> mapParents, int indexStart = 0)
        {
            var type        = map.GetGenericType();
            var constructor = configuration.GetConstructor(map.ClassType);
            var parameters  = constructor.GetParameters();

            foreach (var parameter in parameters)
            {
                var typeConverterType = configuration.TypeConverterCache.GetConverter(parameter.ParameterType).GetType();

                var parameterMap = new ParameterMap(parameter);

                var memberTypeInfo     = parameter.ParameterType.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)
                    {
                        throw new InvalidOperationException($"Configuration '{nameof(configuration.IgnoreReferences)}' can't be true " +
                                                            "when using types without a default constructor. Constructor parameters " +
                                                            "are used and all members including references must be used.");
                    }

                    if (CheckForCircularReference(parameter.ParameterType, mapParents))
                    {
                        throw new InvalidOperationException($"A circular reference was detected in constructor paramter '{parameter.Name}'." +
                                                            "Since all parameters must be supplied for a constructor, this parameter can't be skipped.");
                    }

                    mapParents.AddLast(type);
                    var refMapType = typeof(DefaultClassMap <>).MakeGenericType(parameter.ParameterType);
                    var refMap     = (ClassMap)ReflectionHelper.CreateInstance(refMapType);
                    AutoMapMembers(refMap, configuration, mapParents, Math.Max(map.GetMaxIndex() + 1, indexStart));
                    mapParents.Drop(mapParents.Find(type));

                    var referenceMap = new ParameterReferenceMap(parameter, refMap);
                    if (configuration.ReferenceHeaderPrefix != null)
                    {
                        referenceMap.Data.Prefix = configuration.ReferenceHeaderPrefix(memberTypeInfo.MemberType(), memberTypeInfo.Name);
                    }

                    parameterMap.ReferenceMap = referenceMap;
                }
                else if (configuration.ShouldUseConstructorParameters(parameter.ParameterType))
                {
                    mapParents.AddLast(type);
                    var constructorMapType = typeof(DefaultClassMap <>).MakeGenericType(parameter.ParameterType);
                    var constructorMap     = (ClassMap)ReflectionHelper.CreateInstance(constructorMapType);
                    // Need to use Max here for nested types.
                    AutoMapConstructorParameters(constructorMap, configuration, mapParents, Math.Max(map.GetMaxIndex() + 1, indexStart));
                    mapParents.Drop(mapParents.Find(type));

                    parameterMap.ConstructorTypeMap = constructorMap;
                }
                else
                {
                    parameterMap.Data.TypeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions(), configuration.TypeConverterOptionsCache.GetOptions(parameter.ParameterType), parameterMap.Data.TypeConverterOptions);
                    parameterMap.Data.Index = map.GetMaxIndex() + 1;
                }

                map.ParameterMaps.Add(parameterMap);
            }

            map.ReIndex(indexStart);
        }
コード例 #3
0
ファイル: ClassMap.cs プロジェクト: zhzy0077/CsvHelper
        /// <summary>
        /// Auto maps the given map using constructor parameters.
        /// </summary>
        /// <param name="map">The 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 AutoMapConstructorParameters(ClassMap map, CsvContext context, LinkedList <Type> mapParents, int indexStart = 0)
        {
            var type        = map.GetGenericType();
            var args        = new GetConstructorArgs(map.ClassType);
            var constructor = context.Configuration.GetConstructor(args);
            var parameters  = constructor.GetParameters();

            foreach (var parameter in parameters)
            {
                var parameterMap = new ParameterMap(parameter);

                if (parameter.GetCustomAttributes <IgnoreAttribute>(true).Any() || parameter.GetCustomAttributes <ConstantAttribute>(true).Any())
                {
                    // If there is an IgnoreAttribute or ConstantAttribute, we still need to add a map because a constructor requires
                    // all parameters to be present. A default value will be used later on.

                    ApplyAttributes(parameterMap);
                    map.ParameterMaps.Add(parameterMap);
                    continue;
                }

                var typeConverterType  = context.TypeConverterCache.GetConverter(parameter.ParameterType).GetType();
                var memberTypeInfo     = parameter.ParameterType.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 (context.Configuration.IgnoreReferences)
                    {
                        throw new InvalidOperationException($"Configuration '{nameof(CsvConfiguration.IgnoreReferences)}' can't be true " +
                                                            "when using types without a default constructor. Constructor parameters " +
                                                            "are used and all members including references must be used.");
                    }

                    if (CheckForCircularReference(parameter.ParameterType, mapParents))
                    {
                        throw new InvalidOperationException($"A circular reference was detected in constructor paramter '{parameter.Name}'." +
                                                            "Since all parameters must be supplied for a constructor, this parameter can't be skipped.");
                    }

                    mapParents.AddLast(type);
                    var refMapType = typeof(DefaultClassMap <>).MakeGenericType(parameter.ParameterType);
                    var refMap     = (ClassMap)ObjectResolver.Current.Resolve(refMapType);
                    AutoMapMembers(refMap, context, mapParents, Math.Max(map.GetMaxIndex(isParameter: true) + 1, indexStart));
                    mapParents.Drop(mapParents.Find(type));

                    var referenceMap = new ParameterReferenceMap(parameter, refMap);
                    if (context.Configuration.ReferenceHeaderPrefix != null)
                    {
                        var referenceHeaderPrefix = new ReferenceHeaderPrefixArgs(memberTypeInfo.MemberType(), memberTypeInfo.Name);
                        referenceMap.Data.Prefix = context.Configuration.ReferenceHeaderPrefix(referenceHeaderPrefix);
                    }

                    ApplyAttributes(referenceMap);

                    parameterMap.ReferenceMap = referenceMap;
                }
                else if (context.Configuration.ShouldUseConstructorParameters(new ShouldUseConstructorParametersArgs(parameter.ParameterType)))
                {
                    mapParents.AddLast(type);
                    var constructorMapType = typeof(DefaultClassMap <>).MakeGenericType(parameter.ParameterType);
                    var constructorMap     = (ClassMap)ObjectResolver.Current.Resolve(constructorMapType);
                    // Need to use Max here for nested types.
                    AutoMapConstructorParameters(constructorMap, context, mapParents, Math.Max(map.GetMaxIndex(isParameter: true) + 1, indexStart));
                    mapParents.Drop(mapParents.Find(type));

                    parameterMap.ConstructorTypeMap = constructorMap;
                }
                else
                {
                    parameterMap.Data.TypeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions(), context.TypeConverterOptionsCache.GetOptions(parameter.ParameterType), parameterMap.Data.TypeConverterOptions);
                    parameterMap.Data.Index = map.GetMaxIndex(isParameter: true) + 1;

                    ApplyAttributes(parameterMap);
                }

                map.ParameterMaps.Add(parameterMap);
            }

            map.ReIndex(indexStart);
        }