如何强制调用C#派生方法

时间:2009-08-13 23:45:07

标签: c# class inheritance

我有一个由某个工具生成的类,因此我无法更改它。生成的类非常简单(没有接口,没有虚拟方法):

class GeneratedFoo
{
  public void Write(string p) { /* do something */ }
}

在C#项目中,我们想提供一种方法,以便我们可以插入MyFoo的不同实现。所以我想让MyFoo派生自GeneratedFoo

class MyFoo : GeneratedFoo
{
  public new void Write(string p) { /* do different things */ }
}

然后我有一个CreateFoo方法,它将返回GeneratedFoo或MyFoo类的实例。但是它总是调用GeneratedFoo中的方法。

GeneratedFoo foo = CreateFoo(); // if this returns MyFoo,
foo.Write("1"); // it stills calls GeneratedFoo.Write

这是因为它不是虚方法而被删除。但我想知道是否有一种方法(可能是黑客)让它调用派生方法。

谢谢,
伊恩

7 个答案:

答案 0 :(得分:22)

亚当给了你答案(正确答案)。现在是你要求的黑客攻击的时候了:)


class BaseFoo
{
    public void Write() { Console.WriteLine("Hello simple world"); }
}

class DerFoo : BaseFoo
{
    public void Write() { Console.WriteLine("Hello complicated world"); }
}

public static void Main()
{
    BaseFoo bs = new DerFoo();
    bs.Write();

    bs.GetType().GetMethod("Write").Invoke(bs, null);
}

打印出来:

Hello simple world
Hello complicated world

答案 1 :(得分:6)

无法使方法成为虚拟,没有。非虚方法在编译时静态链接,不能更改。

答案 2 :(得分:6)

编写一个安全播放到派生类型的扩展方法,然后调用那个引用的方法。

public static class Extensions
{
  public static void WriteFoo(this GeneratedFoo foo, string p)
  {
     MyFoo derived = foo as MyFoo;
     if (derived != null)
     {
        derived.Write(p);
     }
     else
     {
        foo.Write(p);
     }
  }
}

然后用

调用它
GeneratedFoo unknownFoo;
unknownFoo.WriteFoo("win");

NB :这是一个肮脏的黑客。一个更清晰的解决方案是问你自己为什么你需要首先使用new修饰符。重载Write(p)的含义会使您的代码对维护者感到困惑。你可以很容易地声明它public void WriteToTarget()或更具体的东西,以避免这种混乱。

答案 3 :(得分:3)

在方法上使用“new”不会覆盖,它隐藏了原始方法。这与多态性完全不同,应该避免,其唯一目的是执行相同功能的方法的协方差/反方差(例如,公共Foo Clone();以及公共新的Bar Clone();)。另一个目的是遗留代码,当一个名称相同的方法被添加到您无法控制的基类时,此时不能更改您的方法名称。

虽然这两个方法共享相同的名称,但它们是完全独立的方法,它占用了类的方法表中的不同插槽,其中覆盖替换了类的方法表中的现有方法。

我的解决方案是使用IFoo等接口,编辑生成的类或使用代理类将其所有方法调用委托给GeneratedFoo实例来实现IFoo。


public DelegatingFoo : IFoo
{
  private GeneratedFoo foo;

  public DelegatingFoo(GeneratedFoo foo) { this.foo = foo; }
  public void Write(string p) { foo.Write(p); }
}

答案 4 :(得分:1)

如果生成的类没有虚方法,那么就不可能。如果您可以修改工具以将Write方法生成为virtual,那么在MyFoo中使用关键字override而不是new来限定Write方法。 第二种选择是在工具运行后编写一个脚本/宏来更改GeneratedFoo的源代码,以便在构建过程中将所需方法注入字符串“virtual”。

答案 5 :(得分:0)

如何在构建系统中添加自定义FX警察规则?

答案 6 :(得分:-1)

您可以使用的方法是实际定义一些全部派生自GeneratedFoo的新类;例如:

public class MyFooBase : GeneratedFoo
{
    public virtual void MyMethod() { ... }
}

public class MyFoo1 : MyFooBase { ... }

public class MyFoo2 : MyFooBase { ... }

这将允许您基本上将虚拟方法添加到生成的类中。