private void TestAssignmentOnStruct <TTarget, TValue>(ref TTarget input, string memberName, TValue value) where TTarget : struct { // Remember that structs are copied when passed into another method. If we're not careful about how we can construct this test // we can end up with a scenario in which the tests can never pass because we're modifying a copy of the struct, not the original // meaning our assertions fail because the modifications were made on a copy // Be VERY CAREFUL modifying this method to ensure you don't accidently introduce such a regression. // To avoid this, we need to do two things // 1. Rather than quoting the value, pass it as a ByRef parameter into a dynamic method // 2. When creating the Dynamic Expression using the binder,we need to use Expression.MakeDynamic() rather than Expression.Dynamic() // The delegate created by Expression.Dynamic() doesn't support ByRef parameters, hence why we have to make the delegate ourselves. // See https://dlr.codeplex.com/discussions/69200 for more details. var binder = new VelocitySetMemberBinder(memberName, new MemberResolver()); var methodParameter = Expression.Parameter(typeof(TTarget).MakeByRefType()); var delegateType = typeof(StructByReferenceDynamicDelegate <TTarget, TValue>); var setExpression = Expression.MakeDynamic(delegateType, binder, methodParameter, Expression.Constant(value)); //var setExpression = Expression.Dynamic(binder, typeof(void), structByRefParam, Expression.Constant(value)); var lambda = Expression.Lambda <StructByReferenceExecution <TTarget> >(setExpression, false, new[] { methodParameter }); var method = lambda.Compile(); method(ref input); }
private void TestAssignmentOnReferenceType <TTarget, TValue>(TTarget input, string memberName, TValue value) where TTarget : class { var binder = new VelocitySetMemberBinder(memberName, new MemberResolver()); InvokeBinder(binder, input, value); }