使用反射来摆脱函数中的前两个参数?

时间:2014-06-23 14:30:00

标签: c# reflection

我有以下代码。是否有可能使用反射来摆脱前两个参数,因为可以在Action assign(或表达式)中找到信息,其形式总是b.P... = a.P...

class A { .... }; var a = new A { P1 = .... } // class A and B are totally different clas
class B { .... }; var b = new B { P1 = .... } // But they have some properties with the same names
....
AssignAndDoSth(a.P1, b.P1, () => b.P1 = a.P1);

private void AssignAndDoSth<T>(T curr, T prev, Action assign) // assign can be Expression
{
   if (!EqualityComparer<T>.Default.Equals(curr, prev))
   {
       assign();
       Do(prev);
       ....
   }
}

2 个答案:

答案 0 :(得分:1)

简短的回答是&#34;我强烈建议反对它&#34 ;;实际上,这实际上是编译器生成的捕获类的实例方法;所以你需要解构目标方法的IL,并根据目标实例的字段评估IL。不好。实际上看起来像是:

var ctx = new SomeType();
ctx.a = new A { P1 = .... };
ctx.b = new B { P1 = .... };
AssignAndDoSth(a.P1, b.P1, new Action(ctx.SomeMethod));
...
class SomeType {
    public A a;
    public B b;
    public void SomeMethod()
    {
        b.P1 = a.P1;
    }
}

另一种方法是重构Expression<Action> - 但这并没有改变所涉及的工作很多 - 它只是提供了一个更友好的API(相对而言)。

无论哪种方式,所有检查都会产生非常重要的性能成本。

答案 1 :(得分:0)

表达式树可能不包含赋值运算符,但可以包含operator ==

  static void AssignAndDoSomething<T>(T curr, T prev, Expression<Func<bool>> assign)
  {
    var logExpr = assign.Body as System.Linq.Expressions.BinaryExpression;
    //output rid of the first parameter
    Console.WriteLine(logExpr.Left);
    //output rid of the second parameter
    Console.WriteLine(logExpr.Right);
    //assign first parameter
    Expression.Lambda<Action>(Expression.Assign(logExpr.Left, Expression.Constant(curr))).Compile()();
    //assign second parameter
    Expression.Lambda<Action>(Expression.Assign(logExpr.Right, Expression.Constant(prev))).Compile()();
  }
  class A
  {
    public int P1;
  }
  class B
  {
    public int P1;
  }

  var a = new A();
  var b = new B();
  AssignAndDoSomething(a.P1, b.P1, () => b.P1 == a.P1);