强制方法从基类调用子类新方法
Posted
技术标签:
【中文标题】强制方法从基类调用子类新方法【英文标题】:Force method from base to call a subclass new method 【发布时间】:2018-10-15 11:40:34 【问题描述】:我的理解是,子类的行为与父类完全相同,除了附加方法或使用new
和override
关键字“重写”的方法。显然,这是不正确的。
请看下面的代码(为了便于阅读,去掉括号)
class BIG
protected void Output(string text = "")
Console.WriteLine("BIG - " + text);
public void CallingOutput()
Output("Outputting...");
class SMALL:BIG
public new void Output(string text = "")
Console.WriteLine("SMALL - " + text);
class Program
static void Main(string[] args)
SMALL foo = new SMALL();
我已经知道可以使用 new
关键字将 BIG.Output(string)
隐藏在 SMALL 中。直接调用时,效果很好。
>> foo.Output("Outputting...")
SMALL - Outputting...
这是与我的理解相冲突的地方。我认为定义class SMALL:BIG
与定义class SMALL
并从BIG 复制粘贴所有方法完全相同。总之,我认为上面的 SMALL 类相当于这样:
class SMALL
public void Output(string text = "")
Console.WriteLine("SMALL - " + text);
public void CallingOutput()
Output("Outputting...");
显然这是不正确的,因为
>> foo.CallingOutput()
BIG - Outputting...
当间接调用时,它仍然使用来自BIG
的原始Output(string)
。
让foo.CallingOutput()
输出的正确方法是什么
"SMALL - Outputting..."
假设我无权访问BIG
并且不允许进行任何更改。而且我不想隐藏CallingOutput()
,因为这基本上是重写课程。
(是的,隐藏CallingOutput()
使其工作)
我在发布之前进行了一些搜索,并在C++
中找到了类似的问题。但是,这个问题的答案是不可能的。
-
我不相信。如此强大的语言,却无法告诉编译器哪个方法是哪个。
这是一种不同的语言,因此该帖子是允许的,因为它不能被视为重复。
【问题讨论】:
在基类中声明方法virtual
,在子类中声明override
,然后基类将大小写,new
在设计上不能这样工作
是的,override
和 new
不可互换。它们有不同的效果。通过显示您对foo
的使用可以使您的问题更清楚; foo
的类型和对象创建。
@abatishchev 如前所述,我不能对 BIG 进行更改。
那就不要继承了。它不是为继承而设计的。相反,您可以使用组合。创建您的 SMALL 类以引用 BIG 对象并根据需要使用它。不适用于所有情况,但可能会带您去您需要去的地方?
那么这是设计使然:您尝试破解 BIG(通过覆盖非虚拟内容来更改其行为)并且框架不允许您这样做(新作品仅在相同类型),因为这不是 BIG 的设计和预期行为方式,抱歉。但是请参阅@itsme86 的答案 - 这是正确的方法(但并不总是适用)
【参考方案1】:
将关键字 new
替换为 override
如下:
class SMALL:BIG
public override void Output(string text = "")
Console.WriteLine("SMALL - " + text);
【讨论】:
我无法对BIG
进行更改,并且BIG.Output()
未标记为虚拟、抽象或覆盖,因此我无法执行此操作。
在你的基类中做
基类是什么意思? BIG 不是基类吗?
是的!看完这篇你就明白了link
我不明白。我在问题和评论中两次声明我不允许对基类进行更改。它就是这样,它没有标记为虚拟、抽象或覆盖,所以我不能使用override
关键字。【参考方案2】:
创建垫片
您不能修改或覆盖现有类中的任何内容,除非它被设计为被覆盖。这是设计使然。
话虽如此,您可以创建一个新的“shim”(传递)类,该类与原始类完全相同,但成员被声明为虚拟。这是通过使用new
和virtual
修饰符来完成的。
一旦你有了 shim 类,你就可以正常地覆盖该方法。示例:
class Big
public void Output(string text) Console.WriteLine("Big - 0", text);
public void CallingOutput()
Output("Outputting...");
class Shim : Big
public new virtual void Output(string text) base.Output(text);
public void CallingOutput()
Output("Outputting...");
现在你有了一个 Shim 类,它允许你想要什么。所以子类化它(而不是 Big),看看会发生什么:
class Small : Shim
public override void Output(string text) Console.WriteLine("Small - 0", text);
测试一下:
Shim s = new Shim();
s.CallingOutput(); //Original behavior
Shim s = new Small();
s.CallingOutput(); //Overridden behavior
输出:
Big - Outputting...
Small - Outputting...
Example on DotNetFiddle
【讨论】:
不,这不是我想要的。目标是让CallingOutput
调用SMALL
中的Output
。在我的问题中,我已经实现了您在示例中的内容,甚至没有使用 Shim
类。请再检查一遍!
正如我所说,你不能拥有你想要的东西,设计。在我的示例中,您可以使用 Shim
而不是 big。它与您已经完成的不同,因为 Small 中的覆盖实际上有效。我将更新示例代码。
好吧,正如我的问题中所述,我不想“重写”CallingOutput
,因为那基本上是重写BIG
。是的,你是对的,如果它一开始就不是这样设计的,那么它不应该被覆盖。
我明白了。对不起,你不能得到你想要的。我建议 shim 比重写 BIG 工作量少,因为您仍然可以访问 this
,仍然能够访问受保护的成员,仍然能够将实例存储在 IEnumerable<BIG>
中或将其作为参数传递BIG
应该在哪里,等等。不过你的电话。以上是关于强制方法从基类调用子类新方法的主要内容,如果未能解决你的问题,请参考以下文章