internal static Expression <Comparison <T2> > CreateCompoundComparer <T1, T2>(Expression <Func <T2, T1> > selector, Expression <Comparison <T1> > comparer) { var newParam1 = Expression.Parameter(selector.Parameters[0].Type, selector.Parameters[0].Name + "_1"); var newParam2 = Expression.Parameter(selector.Parameters[0].Type, selector.Parameters[0].Name + "_2"); var copy1 = ParameterInliner.Inline(selector, newParam1); var copy2 = ParameterInliner.Inline(selector, newParam2); var result = ParameterInliner.Inline(comparer, copy1, copy2); return(Expression.Lambda <Comparison <T2> >(result, newParam1, newParam2)); }
private static Expression <Func <T1, TOutput> > TransformOutput <T1, TFuncOutput, TOutput>( this Expression <Func <T1, TFuncOutput> > func, Expression <Func <TFuncOutput, TOutput> > transform) { Contract.Requires(func != null); Contract.Requires(transform != null); var result = ParameterInliner.Inline(transform, func.Body); return(Expression.Lambda <Func <T1, TOutput> >(result, func.Parameters)); }
private static Expression <Func <T1, T2, TInput, TOutput> > TransformInput3 <T1, T2, T3, TInput, TOutput>( this Expression <Func <T1, T2, T3, TOutput> > func, Expression <Func <TInput, T3> > transform) { Contract.Requires(func != null); Contract.Requires(transform != null); var result = ParameterInliner.Inline(func, func.Parameters[0], func.Parameters[1], transform.Body); var transformParam = transform.Parameters[0]; return(Expression.Lambda <Func <T1, T2, TInput, TOutput> >(result, new[] { func.Parameters[0], func.Parameters[1], transformParam })); }
private static Tuple <Expression, Expression> MakeEqualityAndHashCodeExpressions(ParameterExpression left, ParameterExpression right, ParameterExpression a, Type pType, string pName) { var equalityComparerTypeForPropertyType = typeof(EqualityComparerExpression <>).MakeGenericType(pType); var equalityComparerDefaultProperty = equalityComparerTypeForPropertyType.GetTypeInfo().GetProperty("Default"); var getter = equalityComparerDefaultProperty.GetMethod; var equalityComparerExpressionObject = getter.Invoke(null, null); var equalityComparerExpressionObjectType = equalityComparerExpressionObject.GetType(); var equalityComparerExpression = equalityComparerExpressionObjectType.GetTypeInfo().GetMethod("GetEqualsExpr").Invoke(equalityComparerExpressionObject, null); var hashCodeExpression = equalityComparerExpressionObjectType.GetTypeInfo().GetMethod("GetGetHashCodeExpr").Invoke(equalityComparerExpressionObject, null); var inlinedEqualityExpression = ParameterInliner.Inline((LambdaExpression)equalityComparerExpression, Expression.PropertyOrField(left, pName), Expression.PropertyOrField(right, pName)); var inlinedHashCodeExpression = ParameterInliner.Inline((LambdaExpression)hashCodeExpression, Expression.PropertyOrField(a, pName)); return(Tuple.Create(inlinedEqualityExpression, inlinedHashCodeExpression)); }
/// <summary> /// /// </summary> /// <typeparam name="TKey"></typeparam> /// <typeparam name="TInput"></typeparam> /// <typeparam name="TOutput"></typeparam> /// <typeparam name="TGroupKey"></typeparam> /// <typeparam name="TValue"></typeparam> /// <typeparam name="TAggValue"></typeparam> /// <typeparam name="TState"></typeparam> /// <param name="inputStreamable"></param> /// <param name="initializer"></param> /// <param name="keySelector"></param> /// <param name="attributeSelector"></param> /// <param name="valueSelector"></param> /// <param name="aggregate"></param> /// <returns></returns> public static IStreamable <TKey, TOutput> Pivot <TKey, TInput, TOutput, TGroupKey, TValue, TAggValue, TState>( this IStreamable <TKey, TInput> inputStreamable, Expression <Func <TOutput> > initializer, Expression <Func <TInput, TGroupKey> > keySelector, Expression <Func <TInput, string> > attributeSelector, Expression <Func <TInput, TValue> > valueSelector, Func <Window <CompoundGroupKey <TKey, TGroupKey>, TValue>, IAggregate <TValue, TState, TAggValue> > aggregate) where TOutput : new() { bool sourceHasNullableValues = IsNullable(typeof(TValue)); if (initializer == null) { throw new ArgumentNullException(nameof(initializer)); } var window = new Window <CompoundGroupKey <TKey, TGroupKey>, TValue>(inputStreamable.Properties.GroupNested(keySelector).Select <TValue>(valueSelector, false, false)); var agg = aggregate(window); var valueAgg = agg.TransformInput(valueSelector); var outputPublicFields = typeof(TOutput).GetTypeInfo() .GetFields(BindingFlags.Public | BindingFlags.Instance) .Select(f => Tuple.Create(f.Name, f.FieldType, (MemberInfo)f, !sourceHasNullableValues && IsNullable(f.FieldType))) .Concat( typeof(TOutput).GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.GetIndexParameters().Length == 0) .Select(f => Tuple.Create(f.Name, f.PropertyType, (MemberInfo)f, !sourceHasNullableValues && IsNullable(f.PropertyType)))) .Where(m => m.Item2.GetTypeInfo().IsAssignableFrom(typeof(TAggValue))).ToArray(); var aggArray = outputPublicFields.Select( m => valueAgg.ApplyFilter( Expression.Lambda <Func <TInput, bool> >( Expression.Equal(attributeSelector.Body, Expression.Constant(m.Item1)), attributeSelector.Parameters))); var initialState = Expression.Lambda <Func <TState[]> >(Expression.NewArrayInit(typeof(TState), aggArray.Select(a => a.InitialState().Body))); var state = Expression.Parameter(typeof(TState[]), "state"); var time = Expression.Parameter(typeof(long), "time"); var input = Expression.Parameter(typeof(TInput), "input"); var accumulator = Expression.Lambda <Func <TState[], long, TInput, TState[]> >( Expression.NewArrayInit( typeof(TState), aggArray.Select((a, i) => ParameterInliner.Inline(a.Accumulate(), Expression.ArrayIndex(state, Expression.Constant(i)), time, input))), state, time, input); var deaccumulator = Expression.Lambda <Func <TState[], long, TInput, TState[]> >( Expression.NewArrayInit( typeof(TState), aggArray.Select((a, i) => ParameterInliner.Inline(a.Deaccumulate(), Expression.ArrayIndex(state, Expression.Constant(i)), time, input))), state, time, input); var state1 = Expression.Parameter(typeof(TState[]), "state1"); var state2 = Expression.Parameter(typeof(TState[]), "state2"); var difference = Expression.Lambda <Func <TState[], TState[], TState[]> >( Expression.NewArrayInit( typeof(TState), aggArray.Select((a, i) => ParameterInliner.Inline(a.Difference(), Expression.ArrayIndex(state1, Expression.Constant(i)), Expression.ArrayIndex(state1, Expression.Constant(i))))), state1, state2); var resultSelector = Expression.Lambda <Func <TState[], TAggValue[]> >( Expression.NewArrayInit( typeof(TAggValue), aggArray.Select((a, i) => ParameterInliner.Inline(a.ComputeResult(), Expression.ArrayIndex(state1, Expression.Constant(i))))), state1); var newAgg = new GeneratedAggregate <TInput, TState[], TAggValue[]>(initialState, accumulator, deaccumulator, difference, resultSelector); if (initializer.Body as NewExpression == null) { throw new ArgumentException("Initializer must return a constructor expression.", nameof(initializer)); } var groupkey = Expression.Parameter(typeof(GroupSelectorInput <TGroupKey>), "groupkey"); var aggvalues = Expression.Parameter(typeof(TAggValue[]), "aggvalue"); var keyAssignments = new List <MemberAssignment>(); // Key selector magic! switch (keySelector.Body.NodeType) { case ExpressionType.MemberAccess: { var selector = keySelector.Body as MemberExpression; if (selector.Expression.NodeType == ExpressionType.Parameter) { keyAssignments.Add(Expression.Bind( typeof(TOutput).GetTypeInfo().GetMember(selector.Member.Name).Single(), Expression.PropertyOrField(groupkey, "Key"))); } else { throw new NotImplementedException(); } break; } case ExpressionType.MemberInit: { var memberInit = keySelector.Body as MemberInitExpression; foreach (var init in memberInit.Bindings) { if (init.BindingType != MemberBindingType.Assignment) { throw new NotImplementedException(); } var assign = init as MemberAssignment; if (assign.Expression is MemberExpression rightSide && rightSide.Expression.NodeType == ExpressionType.Parameter) { keyAssignments.Add(Expression.Bind( typeof(TOutput).GetTypeInfo().GetMember(assign.Member.Name).Single(), Expression.PropertyOrField(Expression.PropertyOrField(groupkey, "Key"), rightSide.Member.Name))); }