/// <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(), Reader.context.ReaderConfiguration.TypeConverterOptionsFactory.GetOptions(parameterMap.Data.Parameter.ParameterType), parameterMap.Data.TypeConverterOptions); parameterMap.Data.TypeConverterOptions.CultureInfo = Reader.context.ReaderConfiguration.CultureInfo; // 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); } } }
/// <summary> /// Creates a <see cref="Delegate"/> of type <see cref="Func{T}"/> /// that will create a record of the given type using the current /// reader row. /// </summary> /// <param name="recordType">The record type.</param> protected override Delegate CreateCreateRecordDelegate(Type recordType) { if (Reader.context.ReaderConfiguration.Maps[recordType] == null) { Reader.context.ReaderConfiguration.Maps.Add(Reader.context.ReaderConfiguration.AutoMap(recordType)); } var map = Reader.context.ReaderConfiguration.Maps[recordType]; Expression body; if (map.ParameterMaps.Count > 0) { // This is a constructor paramter type. var arguments = new List <Expression>(); CreateConstructorArgumentExpressionsForMapping(map, arguments); body = Expression.New(Reader.Configuration.GetConstructor(map.ClassType), arguments); } else { var bindings = new List <MemberBinding>(); ExpressionManager.CreateMemberBindingsForMapping(map, recordType, bindings); if (bindings.Count == 0) { throw new ReaderException(Reader.context, $"No members are mapped for type '{recordType.FullName}'."); } if (map.Constructor is NewExpression) { body = Expression.MemberInit((NewExpression)map.Constructor, bindings); } else if (map.Constructor is MemberInitExpression) { var memberInitExpression = (MemberInitExpression)map.Constructor; var defaultBindings = memberInitExpression.Bindings.ToList(); defaultBindings.AddRange(bindings); body = Expression.MemberInit(memberInitExpression.NewExpression, defaultBindings); } else { // This is in case an IContractResolver is being used. var type = ReflectionHelper.CreateInstance(recordType).GetType(); body = Expression.MemberInit(Expression.New(type), bindings); } } var funcType = typeof(Func <>).MakeGenericType(recordType); return(Expression.Lambda(funcType, body).Compile()); }
/// <summary> /// Creates a <see cref="Delegate"/> of type <see cref="Func{T}"/> /// that will create a record of the given type using the current /// reader row. /// </summary> /// <param name="recordType">The record type.</param> protected override Delegate CreateCreateRecordDelegate(Type recordType) { if (Reader.Context.Maps[recordType] == null) { Reader.Context.Maps.Add(Reader.Context.AutoMap(recordType)); } var map = Reader.Context.Maps[recordType]; Expression body; if (map.ParameterMaps.Count > 0) { // This is a constructor parameter type. var arguments = new List <Expression>(); ExpressionManager.CreateConstructorArgumentExpressionsForMapping(map, arguments); var args = new GetConstructorArgs { ClassType = map.ClassType }; body = Expression.New(Reader.Configuration.GetConstructor(args), arguments); } else { var assignments = new List <MemberAssignment>(); ExpressionManager.CreateMemberAssignmentsForMapping(map, assignments); if (assignments.Count == 0) { throw new ReaderException(Reader.Context, $"No members are mapped for type '{recordType.FullName}'."); } body = ExpressionManager.CreateInstanceAndAssignMembers(recordType, assignments); } var funcType = typeof(Func <>).MakeGenericType(recordType); return(Expression.Lambda(funcType, body).Compile()); }
/// <summary> /// Creates a <see cref="Delegate"/> of type <see cref="Action{T}"/> /// that will write the given record using the current writer row. /// </summary> /// <typeparam name="T">The record type.</typeparam> /// <param name="record">The record.</param> protected override Action <T> CreateWriteDelegate <T>(T record) { var type = Writer.GetTypeForRecord(record); if (Writer.Context.WriterConfiguration.Maps[type] == null) { Writer.Context.WriterConfiguration.Maps.Add(Writer.Context.WriterConfiguration.AutoMap(type)); } var recordParameter = Expression.Parameter(typeof(T), "record"); var recordParameterConverted = Expression.Convert(recordParameter, type); // Get a list of all the members so they will // be sorted properly. var members = new MemberMapCollection(); members.AddMembers(Writer.Context.WriterConfiguration.Maps[type]); if (members.Count == 0) { throw new WriterException(Writer.Context, $"No properties are mapped for type '{type.FullName}'."); } var delegates = new List <Action <T> >(); foreach (var memberMap in members) { if (memberMap.Data.WritingConvertExpression != null) { // The user is providing the expression to do the conversion. Expression exp = Expression.Invoke(memberMap.Data.WritingConvertExpression, recordParameterConverted); exp = Expression.Call(Expression.Constant(Writer), nameof(Writer.WriteConvertedField), null, exp); delegates.Add(Expression.Lambda <Action <T> >(exp, recordParameter).Compile()); continue; } if (!Writer.CanWrite(memberMap)) { continue; } Expression fieldExpression; if (memberMap.Data.IsConstantSet) { if (memberMap.Data.Constant == null) { fieldExpression = Expression.Constant(string.Empty); } else { fieldExpression = Expression.Constant(memberMap.Data.Constant); var typeConverterExpression = Expression.Constant(Writer.Configuration.TypeConverterCache.GetConverter(memberMap.Data.Constant.GetType())); var method = typeof(ITypeConverter).GetMethod(nameof(ITypeConverter.ConvertToString)); fieldExpression = Expression.Convert(fieldExpression, typeof(object)); fieldExpression = Expression.Call(typeConverterExpression, method, fieldExpression, Expression.Constant(Writer), Expression.Constant(memberMap.Data)); } } else { if (memberMap.Data.TypeConverter == null) { // Skip if the type isn't convertible. continue; } fieldExpression = ExpressionManager.CreateGetMemberExpression(recordParameterConverted, Writer.Context.WriterConfiguration.Maps[type], memberMap); var typeConverterExpression = Expression.Constant(memberMap.Data.TypeConverter); memberMap.Data.TypeConverterOptions = TypeConverterOptions.Merge(new TypeConverterOptions { CultureInfo = Writer.Context.WriterConfiguration.CultureInfo }, Writer.Context.WriterConfiguration.TypeConverterOptionsCache.GetOptions(memberMap.Data.Member.MemberType()), memberMap.Data.TypeConverterOptions); var method = typeof(ITypeConverter).GetMethod(nameof(ITypeConverter.ConvertToString)); fieldExpression = Expression.Convert(fieldExpression, typeof(object)); fieldExpression = Expression.Call(typeConverterExpression, method, fieldExpression, Expression.Constant(Writer), Expression.Constant(memberMap.Data)); if (type.GetTypeInfo().IsClass) { var areEqualExpression = Expression.Equal(recordParameterConverted, Expression.Constant(null)); fieldExpression = Expression.Condition(areEqualExpression, Expression.Constant(string.Empty), fieldExpression); } } var writeFieldMethodCall = Expression.Call(Expression.Constant(Writer), nameof(Writer.WriteConvertedField), null, fieldExpression); delegates.Add(Expression.Lambda <Action <T> >(writeFieldMethodCall, recordParameter).Compile()); } var action = CombineDelegates(delegates); return(action); }
/// <summary> /// Creates a new instance using the given reader. /// </summary> /// <param name="reader">The reader.</param> public RecordHydrator(CsvReader reader) { this.reader = reader; expressionManager = new ExpressionManager(reader); }
/// <summary> /// Initializes a new instance using the given writer. /// </summary> /// <param name="writer">The writer.</param> public RecordWriter(CsvWriter writer) { Writer = writer; ExpressionManager = new ExpressionManager(writer); }
/// <summary> /// Initializes a new instance using the given writer. /// </summary> /// <param name="writer">The writer.</param> public RecordWriter(CsvWriter writer) { Writer = writer; ExpressionManager = ObjectResolver.Current.Resolve <ExpressionManager>(writer); }
/// <summary> /// Initializes a new instance using the given reader. /// </summary> /// <param name="reader">The reader.</param> public RecordCreator(CsvReader reader) { Reader = reader; ExpressionManager = new ExpressionManager(reader); }
/// <summary> /// Creates a new instance using the given reader. /// </summary> /// <param name="reader">The reader.</param> public RecordHydrator(CsvReader reader) { this.reader = reader; expressionManager = ObjectResolver.Current.Resolve <ExpressionManager>(reader); }