在最近的一次采访中,我被要求编写一个程序,其中列出了实现鸣喇叭界面的不同车辆或其他任何车辆,使用抽象类,然后对不同的车辆使用不同的鸣喇叭.这是我到目前为止所提出的,只要我单独调用这些方法,它就能正常工作.但是当我尝试将它们放入IEnumerable中,然后迭代时,它会显示抽象类的honk,而不是单个类.谁能解释我做错了什么?
using System;
using System.Collections.Generic;
namespace ConsoleHonk
{
class Program
{
static void Main(string[] args)
{
var myList = GetVehicles();
//This doesn't display the correct honk
myList.ForEach(x => x.honk());
}
private static List<IHonker> GetVehicles()
{
var myList = new List<IHonker>();
var myTruck = new Truck();
var myCar = new Car();
var myGoose = new Goose();
myList.Add(myTruck);
myList.Add(myGoose);
myList.Add(myCar);
return myList;
}
}
class Goose : HonkClass
{
public virtual void honk()
{
Console.WriteLine("Quack");
}
}
class Car : HonkClass
{
}
class Truck:HonkClass
{
public virtual void honk()
{
Console.WriteLine("Honk-Honk");
}
}
interface IHonker
{
string horn { get; set; }
void honk();
}
public abstract class HonkClass:IHonker
{
public void honk()
{
Console.WriteLine("Beep");
}
public string horn { get; set; }
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您需要一个抽象基类,因为这是您面试的要求.但是,通常在这种情况下,如果您没有这种人为约束,则根本不应使用基类.您可以让各个车辆直接实现界面.
一般来说,如果没有充分的理由,你不应该使用基类.首先,C#支持实现多个接口,但不支持多重继承.所以,你可以有一个类实现这两个接口IHonkable和ISteerable,但不可两者兼得类继承HonkableBase和SteerableBase.
你的代码的问题是Honk方法没有覆盖抽象类,它们隐藏了它.行为的差异正如您所描述的:
public class HidingVehicle : HonkClass
{
public void Honk()
{
Console.Writeline("Hiding honk!");
}
}
public class OverridingVehicle : HonkClass
{
public override void Honk()
{
Console.Writeline("Overriding honk!");
}
}
public class HonkClass
{
public virtual void Honk()
{
Console.Writeline("Base honk!");
}
}
Run Code Online (Sandbox Code Playgroud)
那么方法可能是:
var myHidingVehicle = new HidingVehicle();
var myOverridingVehicle = new OverridingVehicle();
myHidingVehicle.Honk(); //"Hiding honk!"
myOverridingVehicle.Honk(); //"Overriding honk!"
HonkClass hiddenVehicle = myHidingVehicle;
HonkClass overridenVehicle = myOverridingVehcile;
hiddenVehicle.Honk(); //"Base honk!"
overridenVehicle.Honk(); //"Overriding honk!"
Run Code Online (Sandbox Code Playgroud)
从代码中可以看出,区别在于overriding关键字.
隐藏可能是故意的,但它很少需要,因为它打破了多态性.如果您确实想要隐藏,并且您确定没有更好的选项,则可以使用new方法声明中的关键字来隐藏编译器警告,并使任何读取您隐藏的代码的人都清楚.