Ejemplo n.º 1
0
        /// <summary>
        /// Writes the field to the CSV file.
        /// When all fields are written for a record,
        /// <see cref="IWriter.NextRecord" /> must be called
        /// to complete writing of the current record.
        /// </summary>
        /// <typeparam name="T">The type of the field.</typeparam>
        /// <param name="field">The field to write.</param>
        /// <param name="converter">The converter used to convert the field into a string.</param>
        public virtual void WriteField <T>(T field, ITypeConverter converter)
        {
            var type = field == null ? typeof(string) : field.GetType();

            context.ReusableMemberMapData.TypeConverter = converter;
            if (!context.TypeConverterOptionsCache.TryGetValue(type, out TypeConverterOptions typeConverterOptions))
            {
                typeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions {
                    CultureInfo = context.WriterConfiguration.CultureInfo
                }, context.WriterConfiguration.TypeConverterOptionsCache.GetOptions(type));
                context.TypeConverterOptionsCache.Add(type, typeConverterOptions);
            }

            context.ReusableMemberMapData.TypeConverterOptions = typeConverterOptions;

            var fieldString = converter.ConvertToString(field, this, context.ReusableMemberMapData);

            WriteConvertedField(fieldString);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Writes out the column styles for the record
        /// </summary>
        /// <param name="properties">Properties for the record</param>
        private void WriteColumnStyles(
            ExcelPropertyMapCollection properties)
        {
            // Write the column styles for all the columns
            for (var col = 0; col < properties.Count; col++)
            {
                // Determine if this property is written
                var propertyMap = properties[col];
                if (!CanWrite(propertyMap))
                {
                    continue;
                }

                // Now get the property converter and options
                var data = propertyMap.Data;
                var typeConverterOptions = TypeConverterOptions.Merge(
                    TypeConverterOptionsFactory.GetOptions(data.Property.PropertyType, _configuration.CultureInfo),
                    data.TypeConverterOptions);

                // Write the cell formatting style if defined for this type
                var isDate = data.TypeConverter.ConvertedType == typeof(DateTime);
                var format = isDate ? typeConverterOptions.DateFormat : typeConverterOptions.NumberFormat;
                if (format != null)
                {
                    using (var xlColumn = _sheet.Column(col + 1)) {
                        if (isDate)
                        {
                            xlColumn.Style.DateFormat.Format = format;
                        }
                        else
                        {
                            xlColumn.Style.NumberFormat.Format = format;
                        }
                    }
                }
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Creates the constructor arguments used to create a type.
        /// </summary>
        /// <param name="map">The mapping to create the arguments for.</param>
        /// <param name="argumentExpressions">The arguments that will be added to the mapping.</param>
        protected virtual void CreateConstructorArgumentExpressionsForMapping(ClassMap map, List <Expression> argumentExpressions)
        {
            foreach (var parameterMap in map.ParameterMaps)
            {
                if (parameterMap.ConstructorTypeMap != null)
                {
                    // Constructor paramter type.
                    var arguments = new List <Expression>();
                    CreateConstructorArgumentExpressionsForMapping(parameterMap.ConstructorTypeMap, arguments);
                    var constructorExpression = Expression.New(Reader.Configuration.GetConstructor(parameterMap.ConstructorTypeMap.ClassType), arguments);

                    argumentExpressions.Add(constructorExpression);
                }
                else if (parameterMap.ReferenceMap != null)
                {
                    // Reference type.

                    var referenceBindings = new List <MemberBinding>();
                    ExpressionManager.CreateMemberBindingsForMapping(parameterMap.ReferenceMap.Data.Mapping, parameterMap.ReferenceMap.Data.Parameter.ParameterType, referenceBindings);

                    // This is in case an IContractResolver is being used.
                    var type          = ReflectionHelper.CreateInstance(parameterMap.ReferenceMap.Data.Parameter.ParameterType).GetType();
                    var referenceBody = Expression.MemberInit(Expression.New(type), referenceBindings);

                    argumentExpressions.Add(referenceBody);
                }
                else
                {
                    // Value type.

                    var index = Reader.Configuration.HasHeaderRecord
                                                ? Reader.GetFieldIndex(parameterMap.Data.Name, 0)
                                                : parameterMap.Data.Index;

                    // Get the field using the field index.
                    var        method          = typeof(IReaderRow).GetProperty("Item", typeof(string), new[] { typeof(int) }).GetGetMethod();
                    Expression fieldExpression = Expression.Call(Expression.Constant(Reader), method, Expression.Constant(index, typeof(int)));

                    // Convert the field.
                    var typeConverterExpression = Expression.Constant(parameterMap.Data.TypeConverter);
                    parameterMap.Data.TypeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions {
                        CultureInfo = Reader.Context.ReaderConfiguration.CultureInfo
                    }, Reader.Context.ReaderConfiguration.TypeConverterOptionsCache.GetOptions(parameterMap.Data.Parameter.ParameterType), parameterMap.Data.TypeConverterOptions);

                    // Create type converter expression.
                    var memberMapData = new MemberMapData(null)
                    {
                        Index                = parameterMap.Data.Index,
                        TypeConverter        = parameterMap.Data.TypeConverter,
                        TypeConverterOptions = parameterMap.Data.TypeConverterOptions
                    };
                    memberMapData.Names.Add(parameterMap.Data.Name);
                    Expression typeConverterFieldExpression = Expression.Call(typeConverterExpression, nameof(ITypeConverter.ConvertFromString), null, fieldExpression, Expression.Constant(Reader), Expression.Constant(memberMapData));
                    typeConverterFieldExpression = Expression.Convert(typeConverterFieldExpression, parameterMap.Data.Parameter.ParameterType);

                    fieldExpression = typeConverterFieldExpression;

                    argumentExpressions.Add(fieldExpression);
                }
            }
        }
Ejemplo n.º 4
0
        /// <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);
        }
Ejemplo n.º 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, 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);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Creates the constructor arguments used to create a type.
        /// </summary>
        /// <param name="map">The mapping to create the arguments for.</param>
        /// <param name="argumentExpressions">The arguments that will be added to the mapping.</param>
        public virtual void CreateConstructorArgumentExpressionsForMapping(ClassMap map, List <Expression> argumentExpressions)
        {
            foreach (var parameterMap in map.ParameterMaps)
            {
                if (parameterMap.ConstructorTypeMap != null)
                {
                    // Constructor parameter type.
                    var arguments = new List <Expression>();
                    CreateConstructorArgumentExpressionsForMapping(parameterMap.ConstructorTypeMap, arguments);
                    var constructorExpression = Expression.New(reader.Configuration.GetConstructor(parameterMap.ConstructorTypeMap.ClassType), arguments);

                    argumentExpressions.Add(constructorExpression);
                }
                else if (parameterMap.ReferenceMap != null)
                {
                    // Reference type.

                    var referenceAssignments = new List <MemberAssignment>();
                    CreateMemberAssignmentsForMapping(parameterMap.ReferenceMap.Data.Mapping, referenceAssignments);

                    var referenceBody = CreateInstanceAndAssignMembers(parameterMap.ReferenceMap.Data.Parameter.ParameterType, referenceAssignments);
                    argumentExpressions.Add(referenceBody);
                }
                else
                {
                    // Value type.

                    int index;
                    if (parameterMap.Data.IsNameSet || reader.Configuration.HasHeaderRecord && !parameterMap.Data.IsIndexSet)
                    {
                        // Use name.
                        index = reader.GetFieldIndex(parameterMap.Data.Name, 0);
                    }
                    else
                    {
                        // Use index.
                        index = parameterMap.Data.Index;
                    }

                    // Get the field using the field index.
                    var        method          = typeof(IReaderRow).GetProperty("Item", typeof(string), new[] { typeof(int) }).GetGetMethod();
                    Expression fieldExpression = Expression.Call(Expression.Constant(reader), method, Expression.Constant(index, typeof(int)));

                    // Convert the field.
                    var typeConverterExpression = Expression.Constant(parameterMap.Data.TypeConverter);
                    parameterMap.Data.TypeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions {
                        CultureInfo = reader.Context.ReaderConfiguration.CultureInfo
                    }, reader.Context.ReaderConfiguration.TypeConverterOptionsCache.GetOptions(parameterMap.Data.Parameter.ParameterType), parameterMap.Data.TypeConverterOptions);

                    // Create type converter expression.
                    var memberMapData = new MemberMapData(null)
                    {
                        Index                = parameterMap.Data.Index,
                        TypeConverter        = parameterMap.Data.TypeConverter,
                        TypeConverterOptions = parameterMap.Data.TypeConverterOptions
                    };
                    memberMapData.Names.Add(parameterMap.Data.Name);
                    Expression typeConverterFieldExpression = Expression.Call(typeConverterExpression, nameof(ITypeConverter.ConvertFromString), null, fieldExpression, Expression.Constant(reader), Expression.Constant(memberMapData));
                    typeConverterFieldExpression = Expression.Convert(typeConverterFieldExpression, parameterMap.Data.Parameter.ParameterType);

                    fieldExpression = typeConverterFieldExpression;

                    argumentExpressions.Add(fieldExpression);
                }
            }
        }