/// <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 referenceAssignments = new List <MemberAssignment>(); ExpressionManager.CreateMemberAssignmentsForMapping(parameterMap.ReferenceMap.Data.Mapping, referenceAssignments); var referenceBody = ExpressionManager.CreateInstanceAndAssignMembers(parameterMap.ReferenceMap.Data.Parameter.ParameterType, referenceAssignments); 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); } } }
/// <summary> /// Creates the action delegate used to hydrate a record's members with data from the reader. /// </summary> /// <typeparam name="T">The record type.</typeparam> protected virtual Action <T> CreateHydrateRecordAction <T>() { var recordType = typeof(T); if (reader.Context.ReaderConfiguration.Maps[recordType] == null) { reader.Context.ReaderConfiguration.Maps.Add(reader.Context.ReaderConfiguration.AutoMap(recordType)); } var mapping = reader.Context.ReaderConfiguration.Maps[recordType]; var recordTypeParameter = Expression.Parameter(recordType, "record"); var memberAssignments = new List <Expression>(); foreach (var memberMap in mapping.MemberMaps) { var fieldExpression = expressionManager.CreateGetFieldExpression(memberMap); if (fieldExpression == null) { continue; } var memberTypeParameter = Expression.Parameter(memberMap.Data.Member.MemberType(), "member"); var memberAccess = Expression.MakeMemberAccess(recordTypeParameter, memberMap.Data.Member); var memberAssignment = Expression.Assign(memberAccess, fieldExpression); memberAssignments.Add(memberAssignment); } foreach (var referenceMap in mapping.ReferenceMaps) { if (!reader.CanRead(referenceMap)) { continue; } var referenceAssignments = new List <MemberAssignment>(); expressionManager.CreateMemberAssignmentsForMapping(referenceMap.Data.Mapping, referenceAssignments); var referenceBody = expressionManager.CreateInstanceAndAssignMembers(referenceMap.Data.Member.MemberType(), referenceAssignments); var memberTypeParameter = Expression.Parameter(referenceMap.Data.Member.MemberType(), "referenceMember"); var memberAccess = Expression.MakeMemberAccess(recordTypeParameter, referenceMap.Data.Member); var memberAssignment = Expression.Assign(memberAccess, referenceBody); memberAssignments.Add(memberAssignment); } var body = Expression.Block(memberAssignments); return(Expression.Lambda <Action <T> >(body, recordTypeParameter).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()); }