Skip to content

Instantly share code, notes, and snippets.

@FelicePollano
Created January 18, 2012 11:22
Show Gist options
  • Save FelicePollano/1632522 to your computer and use it in GitHub Desktop.
Save FelicePollano/1632522 to your computer and use it in GitHub Desktop.
Genric SWAP
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()();
}
}
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