Created
January 18, 2012 11:22
-
-
Save FelicePollano/1632522 to your computer and use it in GitHub Desktop.
Genric SWAP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class SwapperTest | |
{ | |
public class Test_ | |
{ | |
public int X { get; set; } | |
public int Y { get; set; } | |
} | |
[TestMethod] | |
public void ExampleWithObject() | |
{ | |
var t = new Test_() { X = 0, Y = 1 }; | |
Swapper.Swap(() => t.X, () => t.Y); | |
Assert.AreEqual(0, t.Y); | |
Assert.AreEqual(1, t.X); | |
} | |
[TestMethod] | |
public void ExampleWithArray() | |
{ | |
int[] array = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; | |
Swapper.Swap(() => array[0], () => array[1]); | |
Assert.AreEqual(2, array[0]); | |
Assert.AreEqual(1, array[1]); | |
} | |
[TestMethod] | |
public void ExampleWithList() | |
{ | |
List<int>array = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; | |
Swapper.Swap(() => array[0], () => array[1]); | |
Assert.AreEqual(2, array[0]); | |
Assert.AreEqual(1, array[1]); | |
} | |
[TestMethod] | |
public void ExampleWithTwoDimensionArray() | |
{ | |
int[,] array = new int[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 9, 10 } }; | |
Swapper.Swap(() => array[0, 0], () => array[4, 1]); | |
Assert.AreEqual(10, array[0, 0]); | |
Assert.AreEqual(1, array[4, 1]); | |
} | |
[TestMethod] | |
public void ExampleWithTwoDimensionSlaggedArray() | |
{ | |
int[][] array = new int[][] { new[] { 1, 2 }, new[] { 3, 4 }, new[] { 5, 6 }, new[] { 7, 8 }, new[] { 9, 10 } }; | |
Swapper.Swap(() => array[0][0], () => array[4][1]); | |
Assert.AreEqual(10, array[0][0]); | |
Assert.AreEqual(1, array[4][1]); | |
} | |
[TestMethod] | |
public void ExampleWithLocals() | |
{ | |
int a = 5; | |
int b=6; | |
Swapper.Swap(() => a, () => b); | |
Assert.AreEqual(6, a); | |
Assert.AreEqual(5, b); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment