2

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

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

例如:

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 中做我想做的事——我没有得到智能感知,但编译器很高兴并且它可以工作:

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

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

4

7 回答 7

6

如果不求助于反射或其他肮脏的技巧,就不能调用派生类的非虚拟方法。如果你想这样做,那么很容易:

// obj is your object reference.
obj.GetType().InvokeMember("MethodName", 
    System.Reflection.BindingFlags.InvokeMethod, null, obj, null /* args */)
于 2009-04-16T18:13:50.417 回答
3

我可能遗漏了一些东西,但为什么不使用这些方法从接口创建和继承呢?

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

于 2009-04-16T18:22:42.253 回答
0

将它们声明为虚拟:

http://msdn.microsoft.com/en-us/library/9fkccyh4(VS.71).aspx

于 2009-04-16T18:14:42.880 回答
0

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

public static class MyExtensions
{
   public static ItemBaseClass CreateNewItem(this BaseClass item)
   {
      return item.GetType().InvokeMember("MethodName", System.Reflection.BindingFlags.InvokeMethod, null, obj, null /* args */);
   }
}
于 2009-04-16T18:26:57.780 回答
0

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

于 2009-04-16T18:30:34.543 回答
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();
    }
}
于 2009-04-16T18:40:42.163 回答
-1

您忘记了子类的方法定义中的“覆盖”关键字。当某些东西被声明为“抽象”时,它根据定义是虚拟的,因此在子类中,您需要将“覆盖”关键字放在方法声明的前面。所以应该工作如下:

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() {...}
}

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

于 2009-04-16T18:35:39.850 回答