// Copyright 2009-2022 Josh Close // This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. // See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. // https://github.com/JoshClose/CsvHelper using CsvHelper.TypeConversion; using System; using System.Collections; using System.Linq.Expressions; using System.Reflection; namespace CsvHelper.Configuration { /// /// Mapping info for a member to a CSV field. /// public class MemberMap : MemberMap { /// /// Creates a new instance using the specified member. /// public MemberMap(MemberInfo? member) { TypeConverterOption = new MemberMapTypeConverterOption(this); Data = new MemberMapData(member); } /// /// When reading, is used to get the field /// at the index of the name if there was a /// header specified. It will look for the /// first name match in the order listed. /// When writing, sets the name of the /// field in the header record. /// The first name will be used. /// /// The possible names of the CSV field. public new virtual MemberMap Name(params string[] names) { if (names == null || names.Length == 0) { throw new ArgumentNullException(nameof(names)); } Data.Names.Clear(); Data.Names.AddRange(names); Data.IsNameSet = true; return this; } /// /// When reading, is used to get the /// index of the name used when there /// are multiple names that are the same. /// /// The index of the name. public new virtual MemberMap NameIndex(int index) { Data.NameIndex = index; return this; } /// /// When reading, is used to get the field at /// the given index. When writing, the fields /// will be written in the order of the field /// indexes. /// /// The index of the CSV field. /// The end index used when mapping to an member. public new virtual MemberMap Index(int index, int indexEnd = -1) { Data.Index = index; Data.IsIndexSet = true; Data.IndexEnd = indexEnd; return this; } /// /// Ignore the member when reading and writing. /// If this member has already been mapped as a reference /// member, either by a class map, or by automapping, calling /// this method will not ignore all the child members down the /// tree that have already been mapped. /// public new virtual MemberMap Ignore() { Data.Ignore = true; return this; } /// /// Ignore the member when reading and writing. /// If this member has already been mapped as a reference /// member, either by a class map, or by automapping, calling /// this method will not ignore all the child members down the /// tree that have already been mapped. /// /// True to ignore, otherwise false. public new virtual MemberMap Ignore(bool ignore) { Data.Ignore = ignore; return this; } /// /// The default value that will be used when reading when /// the CSV field is empty. /// /// The default value. /// Use default on conversion failure. public virtual MemberMap Default(TMember defaultValue, bool useOnConversionFailure = false) { Data.Default = defaultValue; Data.IsDefaultSet = true; Data.UseDefaultOnConversionFailure = useOnConversionFailure; return this; } /// /// The default value that will be used when reading when /// the CSV field is empty. This value is not type checked /// and will use a to convert /// the field. This could potentially have runtime errors. /// /// The default value. /// Use default on conversion failure. public virtual MemberMap Default(string defaultValue, bool useOnConversionFailure = false) { Data.Default = defaultValue; Data.IsDefaultSet = true; Data.UseDefaultOnConversionFailure = useOnConversionFailure; return this; } /// /// The constant value that will be used for every record when /// reading and writing. This value will always be used no matter /// what other mapping configurations are specified. /// /// The constant value. public virtual MemberMap Constant(TMember? constantValue) { Data.Constant = constantValue; Data.IsConstantSet = true; return this; } /// /// Specifies the to use /// when converting the member to and from a CSV field. /// /// The TypeConverter to use. public new virtual MemberMap TypeConverter(ITypeConverter typeConverter) { Data.TypeConverter = typeConverter; return this; } /// /// Specifies the to use /// when converting the member to and from a CSV field. /// /// The of the /// to use. public new virtual MemberMap TypeConverter() where TConverter : ITypeConverter { TypeConverter(ObjectResolver.Current.Resolve()); return this; } /// /// Specifies an expression to be used to convert data in the /// row to the member. /// /// The convert expression. public virtual MemberMap Convert(ConvertFromString convertFromStringFunction) { var instance = convertFromStringFunction.Target != null ? Expression.Constant(convertFromStringFunction.Target) : null; var fieldParameter = Expression.Parameter(typeof(ConvertFromStringArgs), "args"); var methodExpression = Expression.Call ( instance, convertFromStringFunction.Method, fieldParameter ); var lambdaExpression = Expression.Lambda>(methodExpression, fieldParameter); Data.ReadingConvertExpression = lambdaExpression; return this; } /// /// Specifies an expression to be used to convert the object /// to a field. /// /// The convert expression. public virtual MemberMap Convert(ConvertToString convertToStringFunction) { var instance = convertToStringFunction.Target != null ? Expression.Constant(convertToStringFunction.Target) : null; var fieldParameter = Expression.Parameter(typeof(ConvertToStringArgs), "args"); var methodExpression = Expression.Call ( instance, convertToStringFunction.Method, fieldParameter ); var lambdaExpression = Expression.Lambda>(methodExpression, fieldParameter); Data.WritingConvertExpression = lambdaExpression; return this; } /// /// Ignore the member when reading if no matching field name can be found. /// public new virtual MemberMap Optional() { Data.IsOptional = true; return this; } /// /// Specifies an expression to be used to validate a field when reading. /// /// public new virtual MemberMap Validate(Validate validateExpression) { return Validate(validateExpression, args => $"Field '{args.Field}' is not valid."); } /// /// Specifies an expression to be used to validate a field when reading along with specified exception message. /// /// /// public new virtual MemberMap Validate(Validate validateExpression, ValidateMessage validateMessageExpression) { var fieldParameter = Expression.Parameter(typeof(ValidateArgs), "args"); var validateCallExpression = Expression.Call( Expression.Constant(validateExpression.Target), validateExpression.Method, fieldParameter ); var messageCallExpression = Expression.Call( Expression.Constant(validateMessageExpression.Target), validateMessageExpression.Method, fieldParameter ); Data.ValidateExpression = Expression.Lambda(validateCallExpression, fieldParameter); Data.ValidateMessageExpression = Expression.Lambda(messageCallExpression, fieldParameter); return this; } } }