// 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;
}
}
}