/// <summary> /// Writes the header record from the given properties. /// </summary> /// <param name="type">The type of the record.</param> protected virtual void WriteHeader(Type type) { if (configuration.Properties.Count == 0) { configuration.AttributeMapping(type); } var properties = new CsvPropertyMapCollection(); properties.AddRange(configuration.Properties); foreach (var reference in configuration.References) { properties.AddRange(reference.ReferenceProperties); } foreach (var property in properties) { if (!property.IgnoreValue) { WriteField(property.NameValue); } } NextRecord(); hasHeaderBeenWritten = true; }
/// <summary> /// Writes the header record from the given properties. /// </summary> /// <param name="type">The type of the record.</param> public virtual void WriteHeader(Type type) { if (type == null) { throw new ArgumentNullException("type"); } if (!configuration.HasHeaderRecord) { throw new CsvWriterException("Configuration.HasHeaderRecord is false. This will need to be enabled to write the header."); } if (hasHeaderBeenWritten) { throw new CsvWriterException("The header record has already been written. You can't write it more than once."); } if (hasRecordBeenWritten) { throw new CsvWriterException("Records have already been written. You can't write the header after writing records has started."); } if (configuration.Properties.Count == 0) { configuration.AttributeMapping(type); } var properties = new CsvPropertyMapCollection(); properties.AddRange(configuration.Properties); foreach (var reference in configuration.References) { properties.AddRange(reference.ReferenceProperties); } foreach (var property in properties) { if (!property.IgnoreValue) { WriteField(property.NameValue); } } NextRecord(); hasHeaderBeenWritten = true; }
/// <summary> /// Adds the properties from the mapping. This will recursively /// traverse the mapping tree and add all properties for /// reference maps. /// </summary> /// <param name="properties">The properties to be added to.</param> /// <param name="mapping">The mapping where the properties are added from.</param> protected virtual void AddProperties(CsvPropertyMapCollection properties, CsvClassMap mapping) { properties.AddRange(mapping.PropertyMaps); foreach (var refMap in mapping.ReferenceMaps) { AddProperties(properties, refMap.Mapping); } }
/// <summary> /// Creates the write record action for the given type if it /// doesn't already exist. /// </summary> /// <param name="type">The type of the custom class being written.</param> /// <param name="expressionCompiler">The expression compiler.</param> protected virtual void CreateWriteRecordAction(Type type, Func <Expression, ParameterExpression, ParameterExpression, Delegate> expressionCompiler) { if (typeActions.ContainsKey(type)) { return; } var writerParameter = Expression.Parameter(typeof(ICsvWriter), "writer"); var recordParameter = Expression.Parameter(type, "record"); if (configuration.Properties.Count == 0) { configuration.AttributeMapping(type); } // Get a list of all the properties so they will // be sorted properly. var properties = new CsvPropertyMapCollection(); properties.AddRange(configuration.Properties); foreach (var reference in configuration.References) { properties.AddRange(reference.ReferenceProperties); } // A list of expressions that will go inside // the lambda code block. var expressions = new List <Expression>(); foreach (var propertyMap in properties) { if (propertyMap.IgnoreValue) { // Skip ignored properties. continue; } if (string.IsNullOrEmpty(propertyMap.FormatValue) && (propertyMap.TypeConverterValue == null || !propertyMap.TypeConverterValue.CanConvertTo(typeof(string)))) { // Skip if the type isn't convertible. continue; } // So we don't have to access a modified closure. var propertyMapCopy = propertyMap; // Get the reference this property is a part of. var reference = (from r in configuration.References from p in r.ReferenceProperties where p == propertyMapCopy select r).SingleOrDefault(); // Get the current object. Either the param passed in // or a reference property object. var currentRecordObject = reference == null ? (Expression)recordParameter : Expression.Property(recordParameter, reference.Property); Expression fieldExpression = Expression.Property(currentRecordObject, propertyMap.PropertyValue); if (!string.IsNullOrEmpty(propertyMap.FormatValue)) { // Use string.Format instead of TypeConverter. var formatExpression = Expression.Constant(propertyMap.FormatValue); //MethodInfo method; if (configuration.UseInvariantCulture) { var method = typeof(string).GetMethod("Format", new[] { typeof(IFormatProvider), typeof(string), typeof(object) }); fieldExpression = Expression.Convert(fieldExpression, typeof(object)); fieldExpression = Expression.Call(method, Expression.Constant(CultureInfo.InvariantCulture), formatExpression, fieldExpression); } else { var method = typeof(string).GetMethod("Format", new[] { typeof(string), typeof(object) }); fieldExpression = Expression.Convert(fieldExpression, typeof(object)); fieldExpression = Expression.Call(method, formatExpression, fieldExpression); } } else { var typeConverterExpression = Expression.Constant(propertyMap.TypeConverterValue); var convertMethod = Configuration.UseInvariantCulture ? "ConvertToInvariantString" : "ConvertToString"; var method = propertyMap.TypeConverterValue.GetType().GetMethod(convertMethod, new[] { typeof(object) }); fieldExpression = Expression.Convert(fieldExpression, typeof(object)); fieldExpression = Expression.Call(typeConverterExpression, method, fieldExpression); } var areEqualExpression = Expression.Equal(currentRecordObject, Expression.Constant(null)); fieldExpression = Expression.Condition(areEqualExpression, Expression.Constant(string.Empty), fieldExpression); var writeFieldMethodCall = Expression.Call(writerParameter, "WriteField", new[] { typeof(string) }, fieldExpression); expressions.Add(writeFieldMethodCall); } var body = Expression.Block(expressions); var func = expressionCompiler(body, writerParameter, recordParameter); typeActions[type] = func; }
/// <summary> /// Gets the action delegate used to write the custom /// class object to the writer. /// </summary> /// <typeparam name="T">The type of the custom class being written.</typeparam> /// <returns>The action delegate.</returns> protected virtual Action <CsvWriter, T> GetWriteRecordAction <T>() where T : class { var type = typeof(T); if (!typeActions.ContainsKey(type)) { Action <CsvWriter, T> func = null; var writerParameter = Expression.Parameter(typeof(CsvWriter), "writer"); var recordParameter = Expression.Parameter(typeof(T), "record"); if (configuration.Properties.Count == 0) { configuration.AttributeMapping <T>(); } // Get a list of all the properties so they will // be sorted properly. var properties = new CsvPropertyMapCollection(); properties.AddRange(configuration.Properties); foreach (var reference in configuration.References) { properties.AddRange(reference.ReferenceProperties); } // A list of expressions that will go inside // the lambda code block. var expressions = new List <Expression>(); foreach (var propertyMap in properties) { if (propertyMap.IgnoreValue) { // Skip ignored properties. continue; } if (propertyMap.TypeConverterValue == null || !propertyMap.TypeConverterValue.CanConvertTo(typeof(string))) { // Skip if the type isn't convertible. continue; } // So we don't have to access a modified closure. var propertyMapCopy = propertyMap; // Get the reference this property is a part of. var reference = (from r in configuration.References from p in r.ReferenceProperties where p == propertyMapCopy select r).SingleOrDefault(); // Get the current object. Either the param passed in // or a reference property object. var currentRecordObject = reference == null ? (Expression)recordParameter : Expression.Property(recordParameter, reference.Property); Expression fieldExpression = Expression.Property(currentRecordObject, propertyMap.PropertyValue); var typeConverterExpression = Expression.Constant(propertyMap.TypeConverterValue); var convertMethod = Configuration.UseInvariantCulture ? "ConvertToInvariantString" : "ConvertToString"; var method = propertyMap.TypeConverterValue.GetType().GetMethod(convertMethod, new[] { typeof(object) }); fieldExpression = Expression.Convert(fieldExpression, typeof(object)); fieldExpression = Expression.Call(typeConverterExpression, method, fieldExpression); var areEqualExpression = Expression.Equal(currentRecordObject, Expression.Constant(null)); fieldExpression = Expression.Condition(areEqualExpression, Expression.Constant(string.Empty), fieldExpression); var writeFieldMethodCall = Expression.Call(writerParameter, "WriteField", new[] { typeof(string) }, fieldExpression); expressions.Add(writeFieldMethodCall); } var body = Expression.Block(expressions); func = Expression.Lambda <Action <CsvWriter, T> >(body, writerParameter, recordParameter).Compile(); typeActions[type] = func; } return((Action <CsvWriter, T>)typeActions[type]); }