/// <summary> /// Creates a mapper Func for a projection. /// </summary> private Func <Row, T> CreateMapperForProjection <T>(RowSet rows, NewTypeProjection projection) { ICollection <Expression> methodBodyExpressions = new LinkedList <Expression>(); // The input parameter for our Func<Row, T>, a C* Row ParameterExpression row = Expression.Parameter(CassandraRowType, "row"); // poco variable ParameterExpression poco = Expression.Variable(typeof(T), "poco"); var constructorParameters = projection.ConstructorInfo.GetParameters(); var columnIndex = 0; if (constructorParameters.Length == 0) { // Use default constructor // T poco = new T() methodBodyExpressions.Add(Expression.Assign(poco, Expression.New(projection.ConstructorInfo))); } else { var parameterExpressions = new List <Expression>(); if (constructorParameters.Length > rows.Columns.Length) { throw new IndexOutOfRangeException(string.Format("Expected at least {0} column(s), obtained {1}", constructorParameters.Length, rows.Columns.Length)); } for (columnIndex = 0; columnIndex < constructorParameters.Length; columnIndex++) { var c = rows.Columns[columnIndex]; var param = constructorParameters[columnIndex]; var getValueT = GetExpressionToGetColumnValueFromRow(row, c, param.ParameterType); parameterExpressions.Add(getValueT); } // T poco = new T(param1, param2, ...) methodBodyExpressions.Add(Expression.Assign(poco, Expression.New(projection.ConstructorInfo, parameterExpressions))); } // Fill the rest of members with the rest of the column values // ReSharper disable once GenericEnumeratorNotDisposed var membersEnumerator = projection.Members.GetEnumerator(); while (membersEnumerator.MoveNext() && columnIndex < rows.Columns.Length) { var member = membersEnumerator.Current; var c = rows.Columns[columnIndex]; var memberType = GetUnderlyingType(member); var getColumnValue = GetExpressionToGetColumnValueFromRow(row, c, memberType); // poco.SomeFieldOrProp = ... getColumnValue call ... var getValueAndAssign = Expression.Assign( Expression.MakeMemberAccess(poco, member), getColumnValue); // Start with an expression that does nothing if the row is null Expression ifRowValueIsNull = Expression.Empty(); // For collections, make an effort to return an empty collection instead of null if (TryGetCreateEmptyCollectionExpression(c, memberType, out Expression createEmptyCollection)) { // poco.SomeFieldOrProp = ... createEmptyCollection ... ifRowValueIsNull = Expression.Assign(Expression.MakeMemberAccess(poco, member), createEmptyCollection); } var columnIndexExpression = Expression.Constant(columnIndex, IntType); //Expression equivalent to // if (row.IsNull(columnIndex) == false) => getValueAndAssign ... // else => ifRowIsNull ... methodBodyExpressions.Add(Expression.IfThenElse( Expression.IsFalse(Expression.Call(row, IsNullMethod, columnIndexExpression)), getValueAndAssign, ifRowValueIsNull)); columnIndex++; } // The last expression in the method body is the return value, so put our new POCO at the end methodBodyExpressions.Add(poco); // Create a block expression for the method body expressions var methodBody = Expression.Block(new [] { poco }, methodBodyExpressions); // Return compiled expression return(Expression.Lambda <Func <Row, T> >(methodBody, row).Compile()); }
protected override Expression VisitNew(NewExpression node) { Projection = new NewTypeProjection(node.Constructor); return(node); }