c# - c#新手:这段代码没有像我预期的那样工作......为什么?
问题描述
为了更多地了解 C# 中不太常见的结构,我在 codingsight.com 上遇到了这个代码示例:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
MyClassB b = new MyClassB();
MyClassA a = b;
a.abc();
Console.ReadLine();
}
}
class MyClassA
{
public MyClassA()
{
Console.WriteLine("constructor A");
}
public void abc()
{
Console.WriteLine("A");
}
}
class MyClassB : MyClassA
{
public MyClassB()
{
Console.WriteLine("constructor B");
}
public void abc()
{
Console.WriteLine("B");
}
}
}
挑战在于预测输出。在控制台中运行代码会出现:
constructor A
constructor B
A
我打赌我的最后一分钱,输出的第 3 行将是“B”,或“未初始化变量”错误,但实际上它是“A”。为什么?
解决方案
为什么?
因为它是 .NET 语言的一个概念,称为通过继承隐藏。它是这样定义的,微软没有解释为什么要这样做。他们也可以选择任何其他行为,但他们没有。
在评论中你说:
计算机所做的是“某事”,但显然不是代码的意图。
实际上,我们不知道意图是什么。我们需要询问该代码片段的作者。我会说它是有意的,因为这是一个很好的问题,看看有人是否理解了继承的原则。
在标题中,你提到有一个警告——这个警告正是对作者的警告,他没有很好地表达他的意图。或者,作为读者,作者没有充分表达他的意图,这是对你的警告。
警告是
警告 CS0108:“MyClassB.abc()”隐藏了继承的成员“MyClassA.abc()”。如果打算隐藏,请使用 new 关键字。
该警告还告诉我们,作者应该使用new
关键字 onMyClassB.abc()
明确地告诉读者他明确地使用了“通过继承隐藏”。
现在,有什么替代方案?如果你想继承你所期望的,MyClassA.abc()
需要标记为virtual
.
但是,仅此更改并不能像您预期的那样修复继承。还有另一个编译器警告
警告 CS0114:“MyClassB.abc()”隐藏了继承的成员“MyClassA.abc()”。要使当前成员覆盖该实现,请添加 override 关键字。否则添加新关键字。
其中明确指出MyClassB.abc()
也需要标记为override
.
看来你对这个陈述最困惑
MyClassA a = b;
该语句相当于
MyClassA a = (MyClassA) b;
但是由于隐式引用转换,强制转换是多余的:
隐式引用转换是:
[...]
从任何 class_type
S
到任何 class_typeT
,提供S
的都是派生自T
.
(其中 S 是 MyClassB,T 是 MyClassA)
推荐阅读
- powershell - 当帐户来自域 A 并且组来自域 B 时如何删除成员?
- python - 在 Numpy 中以编程方式沿其所有轴裁剪数组
- php - 将数量链接到 Woocommerce 中的产品变体
- python - 使用 SQLAlchemy 将用户和限制计数添加到 SQL
- postgresql - 在没有原始 SQL 的情况下在 Ecto 中使用 Postgres UPDATE ... FROM
- python - 如何检测 sampleID 中的异常值
- javascript - Javascript:按属性从具有重复元素的数组构造数组
- android - 如何在已经活跃的应用程序中开发一项功能(需要 Facebook 的 user_friends 权限)?
- javascript - x轴日期时间标签的Highchart高级格式
- javascript - 有什么方法可以使用 webpack 将编辑保存到原始路径中的文件,同时我也可以调试?