C#在运行时更改类方法

时间:2010-05-03 16:40:31

标签: c# .net runtime

我需要扩展实例的行为,但我无法访问该实例的原始源代码。例如:

/* I don't have the source code for this class, only the runtime instance */
Class AB
{
  public void execute();
}

在我的代码中,我会拦截每次执行的调用,计算一些sutff,然后调用原始执行,类似

/* This is how I would like to modify the method invokation */
SomeType m_OrgExecute;

{
    AB a = new AB();
    m_OrgExecute = GetByReflection( a.execute );
    a.execute = MyExecute;
}

void MyExecute()
{
    System.Console.Writeln( "In MyExecute" );
    m_OrgExecute();
}

这可能吗?

有没有人能解决这个问题?

10 个答案:

答案 0 :(得分:5)

看起来你想要Decorator pattern

class AB
{
   public void execute() {...}
}

class FlaviosABDecorator : AB
{
   AB decoratoredAB;

   public FlaviosABDecorator (AB decorated)
   {
       this.decoratedAB = decorated;
   }

   public void execute()
   {
       FlaviosExecute();  //execute your code first...
       decoratedAB.execute();
   }

   void FlaviosExecute() {...}
}

然后,您必须修改使用AB对象的代码。

//original code
//AB someAB = new AB();

//new code
AB originalAB = new AB();
AB someAB = new FlaviosABDecorotor(originalAB);

/* now the following code "just works" but adds your method call */

答案 1 :(得分:3)

没有办法直接通过反射等来做到这一点。

为了让您自己的代码像这样注入,您需要创建其程序集的修改版本,并使用某种形式的code injection。您不能只是在运行时“更改任意程序集的方法”。

答案 2 :(得分:2)

我会看看PostSharp。它可以“重新连接”现有的已编译程序集,以添加您要查找的前后处理类型。我不是百分百肯定它会解决你的需求,但很有可能。

http://www.sharpcrafters.com/aop.net

答案 3 :(得分:2)

您可以使用动态代理,例如Castle Proxy

答案 4 :(得分:1)

因为我喜欢组合而不是继承(并且因为如果密封了类,继承可能不是一个选项),我会将AB包装在我自己的类FlaviosAB中,就像这样......

public class FlaviosAB
{
    private AB _passThrough;
    public FlaviosAB(){
        _passThrough = new AB();
    }

    public void execute()
    {
        //Your code...
        Console.WriteLine("In My Execute");
        //Then call the passThrough's execute.
        _passThrough.execute();
    }
}

答案 5 :(得分:0)

如果AB未密封,则可以继承该类并覆盖该方法。在这种情况下使用新的

class ABChild : AB {
    public new void execute() {
        System.Console.Writeln( "In MyExecute" );
    }
}

根据评论,你应该在ABChild类中调用这个 new 方法:

void Invoke() {
    ABChild a = new ABChild();
    a.execute();
}

希望它有所帮助!!

答案 6 :(得分:0)

您总是可以从类继承并覆盖execute()方法(如果类没有被密封,并且该方法至少不是私有的。)

答案 7 :(得分:0)

您可以使用包装类:

Class ABWrapper
{
  private AB m_AB;

  ABWrapper( AB ab )
  {
    m_AB = new AB();
  }

  public void execute()
  {
    // Do your stuff, then call original method
    m_AB.execute();
  }
}

AB实现接口时,这是一个很好的方法(尽管你没有提到)。在这种情况下,ABWrapper应该实现相同的接口。当您使用 factory 甚至依赖注入创建AB实例时,您可以使用包装器轻松替换它们。

答案 8 :(得分:0)

您可以实施动态代理。查找更多信息here

基本上,您正在扩展基类并使用您的方法覆盖某些方法。现在您需要重新分配由您的实例调用的对象,并且所有调用将首先通过您的对象。

答案 9 :(得分:0)

也许这个Stackoverflow thread的面向方面编程(AOP)解决方案之一会派上用场......