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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/757371/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 00:03:07  来源:igfitidea点击:

How do I call a subclass method on a baseclass object?

c#inheritancec#-2.0polymorphism

提问by Michael Haren

I'm using a library that generates a bunch of classes for me.

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

These classes all inherit from a common base class but that base class doesn't define a couple methods that are common to all subclasses.

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

For example:

例如:

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

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

Unfortunately, the base class doesn't have these methods. This would be great:

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

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!
}

Since there is a common base class for my A+B objects and a common base class for the Item objects, I had hoped to benefit from the wonderful world of polymorphism.

因为我的 A+B 对象有一个公共基类,Item 对象有一个公共基类,所以我希望能从多态的美妙世界中受益。

Unfortunately, since the common methods aren't actually present in the base class, I can't call them virtually. e.g., this would be perfect:

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

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

Obviously casting would work but then I'd need to know which type I had which would negate the benefits.

显然,转换会起作用,但是我需要知道我拥有哪种类型会抵消好处。

How can I "force" a call to these methods? I'm not worried about getting an object that doesn't implement the method I'm trying to call. I can actually do what I want in VB--I don't get intellisense but the compiler's happy and it works:

如何“强制”调用这些方法?我不担心得到一个没有实现我试图调用的方法的对象。我实际上可以在 VB 中做我想做的事情——我没有得到智能感知,但编译器很高兴,它可以工作:

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

Againt, I have no control over these classes (which I think rules out partial classes).

再说一次,我无法控制这些类(我认为这排除了部分类)。

采纳答案by Mehrdad Afshari

You cannot call a non-virtual method of a derived class without resorting to reflection or other dirty tricks. If you want to do it, it's easy then:

你不能在不诉诸反射或其他肮脏技巧的情况下调用派生类的非虚拟方法。如果你想这样做,那么很容易:

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

回答by Lucero

I might be missing something, but why not make and inherit from an interface with those methods?

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

If you are in control of the creation process for the instances, you might get what you want by inheriting from the classes which you didn't write and add then interface (no code needs to be written, the compiler will map the interface to the existing non-virtual methods).

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

回答by Scott Ivey

If you're using Visual Studio 2008 - you can create an extension method for the base class. Inside that extension method, you'd do the cast and call the subclass's method. This should work for 2.0 framework targeted projects as well, as long as you're compiling from withing VS 2008. Borrowing the other suggested reflection code, you could do the following...

如果您使用的是 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 */);
   }
}

回答by Lucero

Another possibility is to use some proxy mechanism, such as a RealProxy (not very efficient in terms of performance though) or better by using dynamically created DynamicMethods so that the overhead of using reflection is only there once per type to support, while keeping it as flexible as the reflection method. This pays off big when you need to call the method several times, but it requires some MSIL knowledge.

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

回答by Kevin Anderson

You forgot the "override" keyword in your sub-classes' method definitions. When something's declared "abstract" it is by definition virtual, and thus in the sub-class you need to put the "override" keyword in front of the method declaration. So what should work is below:

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

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

This should work exactly as you want in your usage example.

这应该完全符合您在使用示例中的要求。

回答by MStodd

Problem #1: your subclasses aren't overriding anything Problem #2: your subclasses have different function signatures than your base class

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

Make sure your signatures are correct, and if you're overriding them, mark them virtual and not abstract. You'll have to add an empty body to the base class virtual functions if you don't want them to do anything.

确保您的签名是正确的,如果您要覆盖它们,请将它们标记为虚拟而不是抽象。如果您不想让它们做任何事情,则必须向基类虚函数添加一个空体。

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