繁体   English   中英

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

[英]How to force call a C# derived method

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

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

因为这不是虚拟方法,所以可以避免这种情况。 但是我想知道是否有一种方法(也许是hack)使其称为派生方法。

谢谢,
伊恩

亚当给你答案(正确的答案)。 现在是时候要求您入侵了:)


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

如果无法将方法虚拟化,则不会。 非虚拟方法在编译时是静态链接的,不能更改。

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

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

注意 :这是一个肮脏的hack。 一个更清晰的解决方案是问自己, 为什么首先需要使用new修饰符。 重载Write(p)的含义会使维护人员感到困惑。 您可以很容易地将其声明为public void WriteToTarget()或更具体的名称,以首先避免这种混淆。

在一个方法上使用“ new”不会被覆盖,它会隐藏原始方法。 这与多态性完全不同,应该避免,它的唯一目的是实现相同功能的方法(例如public Foo Clone()和public new 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方法。 第二种选择是编写脚本/宏以在工具运行后在所需方法之前插入字符串“ virtual”来更改GeneratedFoo的源代码,这是构建过程的一部分。

添加到构建系统的自定义FX cop规则如何处理?

您可以使用的一种方法是实际上定义一些新类,这些类都从GeneratedFoo派生。 例如:

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

public class MyFoo1 : MyFooBase { ... }

public class MyFoo2 : MyFooBase { ... }

这实际上将使您可以将虚拟方法添加到生成的类中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM