Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用反射消除函数中的前两个参数?_C#_Reflection - Fatal编程技术网

C# 使用反射消除函数中的前两个参数?

C# 使用反射消除函数中的前两个参数?,c#,reflection,C#,Reflection,我有以下代码。由于信息可以在操作分配(或表达式)中找到,因此是否可以使用反射来去除前两个参数,该信息的形式始终为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

我有以下代码。由于信息可以在
操作分配
(或表达式)中找到,因此是否可以使用反射来去除前两个参数,该信息的形式始终为
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);
       ....
   }
}
A类{….};var a=新的a{P1=..}//类a和类B是完全不同的类
B类{……};var b=new b{P1=..}//但是它们有一些同名的属性
....
AssignAndDoSth(a.P1,b.P1,()=>b.P1=a.P1);
私有void AssignAndDoSth(T curr,T prev,Action assign)//assign可以是表达式
{
如果(!EqualityComparer.Default.Equals(当前,上一个))
{
赋值();
Do(上一页);
....
}
}
简短的回答是“我强烈反对”;实际上,这实际上是编译器生成的捕获类的实例方法;因此,您需要解构目标方法的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;
    }
}
另一种方法是重构为
表达式
——但这并不会改变所涉及的工作——它只是提供了一个更友好的API(相对而言)


无论哪种方式,所有这些检查都会带来不小的性能代价。

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

  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);
static void AssignAndDoSomething(T curr,T prev,Expression assign)
{
var logExpr=assign.Body为System.Linq.Expressions.BinaryExpression;
//第一个参数的输出
控制台写入线(logExpr.Left);
//输出第二个参数
控制台写入线(logExpr.Right);
//分配第一个参数
Expression.Lambda(Expression.Assign(logExpr.Left,Expression.Constant(curr))).Compile();
//指定第二个参数
Expression.Lambda(Expression.Assign(logExpr.Right,Expression.Constant(prev))).Compile();
}
甲级
{
公共int P1;
}
B类
{
公共int P1;
}
var a=新的a();
var b=新的b();
分配和剂量测量(a.P1,b.P1,()=>b.P1==a.P1);

那么为什么不同时去掉T curr和T prev呢?为什么要走反射的黑暗道路?您当前的代码有什么问题吗?您可以将
表达式
用作curr和prev的类型,并为赋值创建一个新的表达式树,编译并执行它。@Karthik说得对。我已经更新了这个问题。@dcastro用户将更容易使用该功能。函数中不需要冗余信息。我支持Marc,技术上是可行的。但是如果你能使用一个非常简单的表达式,这实际上会更麻烦,例如()=>x(那么它只是从动作的字节2开始读取字段引用)。但是,如果您使用局部变量与静态引用,并且如果equal根据类型改变了它的功能(例如,在decimal上equal生成的表达式与在int上equal不同),那么这个等式和事实意味着它很快就会变得混乱。获取该字段的名称相对便宜,获取其值的速度较慢。该函数将在UI事件处理程序中调用,因此性能不受影响。是,函数可以将表达式而不是动作作为参数类型。