如何在基类对象上调用子类方法?

时间:2009-04-16 18:10:18

标签: c# inheritance c#-2.0 polymorphism

我正在使用一个为我生成一堆类的库。

这些类都继承自公共基类,但该基类没有定义所有子类共有的几个方法。

例如:

SubClassA : BaseClass{
  void Add(ItemA item) {...}
  ItemA CreateNewItem() {...}
}

SubClassB: BaseClass{
  void Add(ItemB item) {...}
  ItemB CreateNewItem() {...}
}

不幸的是,基类没有这些方法。这会很棒:

BaseClass{
  // these aren't actually here, I'm just showing what's missing:
  abstract void Add(ItemBaseClass item);  // not present!
  abstract ItemBaseClass CreateNewItem(); // not present!
}

由于我的A + B对象有一个共同的基类,而Item对象有一个共同的基类,我原本希望从多态的奇妙世界中受益。

不幸的是,由于常用方法实际上并不存在于基类中,我无法虚拟地调用它们。例如,这将是完美的:

BaseClass Obj;
Obj = GetWorkUnit(); // could be SubClassA or SubClassB

ItemBaseClass Item = Obj.CreateNewItem(); // Compile Fail: CreateNewItem() isn't in the base class

Item.DoSomething();

Obj.Add(Item); // Compile Fail: Add(...) isn't in the base class

显然,施法可行,但后来我需要知道哪种类型可以否定好处。

如何“强制”调用这些方法?我并不担心得到一个没有实现我试图调用的方法的对象。我实际上可以在VB中做我想做的事情 - 我没有得到intellisense但是编译器很开心并且它有效:

CType(Obj, Object).Add(Item) // Note: I'm using C#--NOT VB

Againt,我无法控制这些类(我认为排除了部分类)。

7 个答案:

答案 0 :(得分:6)

如果不使用反射或其他脏技巧,则无法调用派生类的非虚方法。如果你想这样做,那么很容易:

// obj is your object reference.
obj.GetType().InvokeMember("MethodName", 
    System.Reflection.BindingFlags.InvokeMethod, null, obj, null /* args */)

答案 1 :(得分:3)

我可能会遗漏一些东西,但为什么不从这些方法的界面中制作和继承呢?

如果您控制实例的创建过程,您可以通过继承您未编写的类来获得所需的内容,然后添加接口(无需编写代码,编译器将映射接口到现有的非虚方法。)

答案 2 :(得分:0)

答案 3 :(得分:0)

如果您使用的是Visual Studio 2008,则可以为基类创建扩展方法。在该扩展方法中,您将执行转换并调用子类的方法。这也应该适用于2.0框架目标项目,只要您使用VS 2008进行编译。借用其他建议的反射代码,您可以执行以下操作...

public static class MyExtensions
{
   public static ItemBaseClass CreateNewItem(this BaseClass item)
   {
      return item.GetType().InvokeMember("MethodName", System.Reflection.BindingFlags.InvokeMethod, null, obj, null /* args */);
   }
}

答案 4 :(得分:0)

另一种可能性是使用一些代理机制,例如RealProxy(在性能方面效率不是很高)或者通过使用动态创建的DynamicMethods更好,这样使用反射的开销只有每种类型支持一次,而保持它像反射方法一样灵活。当你需要多次调用该方法时,这会得到很大回报,但它需要一些MSIL知识。

答案 5 :(得分:0)

问题#1:你的子类没有覆盖任何东西 问题#2:您的子类具有与基类不同的函数签名

确保您的签名正确无误,如果您要覆盖它们,请将它们标记为虚拟而非抽象。如果您不希望它们执行任何操作,则必须向基类虚函数添加一个空体。

class ItemBase{}

class ItemA : ItemBase{}

class ItemB : ItemBase{}

class BaseClass
{
    public virtual void Add(ItemBase item){}
    public virtual ItemBase CreateItem() { return null; }
}

class ClassA : BaseClass
{
    public override void Add(ItemBase item)
    {
        //do whatever
        throw new NotImplementedException();
    }

    public ItemBase CreateItem()
    {
        //create an ItemBase and return
        throw new NotImplementedException();
    }
}

答案 6 :(得分:-1)

您忘记了子类的方法定义中的“override”关键字。当某些东西被声明为“抽象”时,它按照定义是虚拟的,因此在子类中,您需要将“override”关键字放在方法声明的前面。那么应该做些什么呢:

BaseClass{
  abstract void Add(ItemBaseClass item);  // not present!
  abstract ItemBaseClass CreateNewItem(); // not present!
}

SubClassA : BaseClass{
  override void Add(ItemA item) {...}
  override ItemA CreateNewItem() {...}
}

SubClassB: BaseClass{
  override void Add(ItemB item) {...}
  override ItemB CreateNewItem() {...}
}

这应该在您的使用示例中完全按照您的意愿工作。