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

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

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 

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

谢谢,
伊恩

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

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

 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); } 

打印出来:

你好简单的世界
你好复杂的世界

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

 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"); 

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

在方法上使用“new”不会覆盖,它隐藏了原始方法。 这与多态性完全不同,应该避免,其唯一目的是执行相同function的方法的协方差/反演方差(例如,公共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); } } 

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

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

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

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

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