- public class Swapper
- {
- public static void Swap<T>(Expression<Func<T>> left, Expression<Func<T>> right)
- {
- var lvalue = left.Compile()();
- var rvalue = right.Compile()();
- switch (left.Body.NodeType)
- {
- case ExpressionType.ArrayIndex:
- var binaryExp = left.Body as BinaryExpression;
- AssignTo(rvalue, binaryExp);
- break;
- case ExpressionType.Call:
- var methodCall = left.Body as MethodCallExpression;
- AssignTo(rvalue, methodCall);
- break;
- default:
- AssignTo(left, rvalue);
- break;
- }
- switch (right.Body.NodeType)
- {
- case ExpressionType.ArrayIndex:
- var binaryExp = right.Body as BinaryExpression;
- AssignTo(lvalue, binaryExp);
- break;
- case ExpressionType.Call:
- var methodCall = right.Body as MethodCallExpression;
- AssignTo(lvalue, methodCall);
- break;
- default:
- AssignTo(right, lvalue);
- break;
- }
- }
- private static void AssignTo<T>(T value, MethodCallExpression methodCall)
- {
- var setter = GetSetMethodInfo(methodCall.Method.DeclaringType,methodCall.Method.Name);
- Expression.Lambda<Action>(
- Expression.Call(methodCall.Object, setter, Join(methodCall.Arguments, Expression.Constant(value)))
- ).Compile()();
- }
- private static Expression[] Join(ReadOnlyCollection<Expression> args,Expression exp)
- {
- List<Expression> exps = new List<Expression>();
- exps.AddRange(args);
- exps.Add(exp);
- return exps.ToArray();
- }
- private static MethodInfo GetSetMethodInfo(Type target, string name)
- {
- var setName = Regex.Replace(name, "get", new MatchEvaluator((m) =>
- {
- return m.Value.StartsWith("g")?"set":"Set";
- })
- ,RegexOptions.IgnoreCase);
- var setter = target.GetMethod(setName);
- if (null == setter)
- {
- throw new Exception("can't find an expected method named:" + setName);
- }
- return setter;
- }
- private static void AssignTo<T>(Expression<Func<T>> left, T value)
- {
- Expression.Lambda<Func<T>>(Expression.Assign(left.Body, Expression.Constant(value))).Compile()();
- }
- private static void AssignTo<T>(T value, BinaryExpression binaryExp)
- {
- Expression.Lambda<Func<T>>(Expression.Assign(Expression.ArrayAccess(binaryExp.Left, binaryExp.Right), Expression.Constant(value))).Compile()();
- }
- }