Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/289.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c#多态性。从基类转换为派生类_C#_Polymorphism - Fatal编程技术网

c#多态性。从基类转换为派生类

c#多态性。从基类转换为派生类,c#,polymorphism,C#,Polymorphism,我对C#中的这段代码有一个疑问(假设函数ManageCars在主程序中)。 代码应该可以工作,但我的问题是:这是使用多态性的正确方法吗?从汽车到法拉利是正确的还是糟糕的编程方式?我发现的唯一问题是,为了管理所有车型(法拉利、梅赛德斯……),我需要一个很长的开关/外壳。 你的意见是什么 class Car { string _plate = ""; public string Plate { get { return _plate; } s

我对C#中的这段代码有一个疑问(假设函数ManageCars在主程序中)。 代码应该可以工作,但我的问题是:这是使用多态性的正确方法吗?从汽车到法拉利是正确的还是糟糕的编程方式?我发现的唯一问题是,为了管理所有车型(法拉利、梅赛德斯……),我需要一个很长的开关/外壳。 你的意见是什么

class Car
{
    string _plate = "";

    public string Plate
    {
        get { return _plate; }
        set { _plate = value; }
    }

}
class Ferrari : Car
{
    string specialName = "";

    public string SpecialName
    {
        get { return specialName; }
        set { specialName = value; }
    }

    Ferrari (Car obj )
    {
        specialName = (obj is Ferrari) ? ((Ferrari)obj).SpecialName : "";
    }
}

static void ManageCars (Car A)
{
    if (A is Ferrari) 
    {
        Ferrari B= (Ferrari) A;
        Console.Writeline("This is a Ferrari! specialName is " + B.SpecialName);
    }
    //else if(A is Mercedes)
    //{
            ...
    //}
    else
    {
        Console.Writeline("This is simple car");
    }
}

在类中,您应该创建如下所示的虚拟函数:

public virtual void ManageCars()
{
    Console.Writeline("This is simple car");
}
通过重写基类方法,所有派生类都可以具有派生功能。例如:

public override void ManageCars()
{
    Console.Writeline("This is a Ferrari! specialName is " + B.SpecialName);
}
Car[] cars = new Car[];
// Retrieve your cars collection here
foreach (Car car in cars)
{
   if (car is BatMobile)
   {
      BatMobile batCar = (BatMobile)car;
      batCar.fly();      // No way to invoke this method unless we are sure it's    
                         // a BatMobile

   }
}
foreach (Car car in cars) 
{
   car.ManageCars();
}

然后,对于每个派生的car,您可以只调用ManageCars而不使用任何switch语句。

我建议在这种情况下不要使用多态性。你会得到很多子类。创建一个汽车类,并添加诸如“Make”、“Model”、“Color”、“Horsepower”等属性。根据经验,相信我,这将在将来为您省去很多麻烦


话虽如此,您可以使用“as”操作符检查基类是否是子类的实例,但它通常表明体系结构不好。

当使用多态性时,您通常在需要检索特殊方法时使用从基类到专用类的转换。例如,假设您有

public class Batmobile: Car 
{
   public void fly() 
   {
     // flying algo here
   }
}
然后,如果您正在迭代基类型的集合,并且需要在可能的情况下应用特殊行为,那么您可以将基类强制转换为专用类,并调用特殊行为

例如:

public override void ManageCars()
{
    Console.Writeline("This is a Ferrari! specialName is " + B.SpecialName);
}
Car[] cars = new Car[];
// Retrieve your cars collection here
foreach (Car car in cars)
{
   if (car is BatMobile)
   {
      BatMobile batCar = (BatMobile)car;
      batCar.fly();      // No way to invoke this method unless we are sure it's    
                         // a BatMobile

   }
}
foreach (Car car in cars) 
{
   car.ManageCars();
}
但是在上面介绍的例子中,最好利用C#语言的多态能力,使用虚拟方法调用和后期绑定

如@Jonathan Riger所示,您创建了一个类似ManageCars的虚拟方法,然后在每个特殊类型的子体中重写它。借助于运行时的多态性,将通过基类的编译时调用从相应实例调用正确的方法

例如

车内课程:

public virtual void ManageCars()
{
    Console.Writeline("This is simple car");
}
public override void ManageCars()
{
    Console.Writeline("This is a Ferrari! specialName is " + B.SpecialName);
}
public override void ManageCars()
{
    Console.Writeline("This is a BatMobile car, it can fly really high !");
}
Car[] cars = new Car[3];
cars[0] = new Car();
cars[1] = new Ferrari();
cars[2] = new BatMobile();
法拉利级:

public virtual void ManageCars()
{
    Console.Writeline("This is simple car");
}
public override void ManageCars()
{
    Console.Writeline("This is a Ferrari! specialName is " + B.SpecialName);
}
public override void ManageCars()
{
    Console.Writeline("This is a BatMobile car, it can fly really high !");
}
Car[] cars = new Car[3];
cars[0] = new Car();
cars[1] = new Ferrari();
cars[2] = new BatMobile();
在蝙蝠车类中:

public virtual void ManageCars()
{
    Console.Writeline("This is simple car");
}
public override void ManageCars()
{
    Console.Writeline("This is a Ferrari! specialName is " + B.SpecialName);
}
public override void ManageCars()
{
    Console.Writeline("This is a BatMobile car, it can fly really high !");
}
Car[] cars = new Car[3];
cars[0] = new Car();
cars[1] = new Ferrari();
cars[2] = new BatMobile();
现在假设我们有:

public virtual void ManageCars()
{
    Console.Writeline("This is simple car");
}
public override void ManageCars()
{
    Console.Writeline("This is a Ferrari! specialName is " + B.SpecialName);
}
public override void ManageCars()
{
    Console.Writeline("This is a BatMobile car, it can fly really high !");
}
Car[] cars = new Car[3];
cars[0] = new Car();
cars[1] = new Ferrari();
cars[2] = new BatMobile();
如果在数组上循环并调用ManageCar()方法,例如:

public override void ManageCars()
{
    Console.Writeline("This is a Ferrari! specialName is " + B.SpecialName);
}
Car[] cars = new Car[];
// Retrieve your cars collection here
foreach (Car car in cars)
{
   if (car is BatMobile)
   {
      BatMobile batCar = (BatMobile)car;
      batCar.fly();      // No way to invoke this method unless we are sure it's    
                         // a BatMobile

   }
}
foreach (Car car in cars) 
{
   car.ManageCars();
}

…它将在运行时检索正确的方法,即使编译时调用是基于基类的,而基类不知道方法的特殊性:这是多态性魔力的一部分:)

不确定ManageCars应该做什么-但是如果它做的是每个派生类特有的事情,然后,您可能应该在基本Car类上有一个虚拟Manage方法,并在每个派生类中重写它。然后,您可以在ManagerCars中使用class A.Manage(),而不必担心类型。如果您将一个对象实例化为
Car
,那么它将始终无法通过
obj is Ferrari
检查,这个问题更适合于此。在本例中,您可以“从基础转换为派生”的唯一原因是因为对象已经是法拉利,您刚刚在构造函数
Ferrari(Car obj)
中接受了它的
Car
视图。你不能把一个被构造成汽车的东西扔给法拉利,这会让你的问题变得毫无意义。我建议你阅读并实践坚实的原则。特别是利斯科夫替换,非常清楚,谢谢。我想描述的是蝙蝠车的例子,它能飞……但是如果我有很多机器模型,每一个都有一个特殊的能力(一个能飞,一个游泳等等),这是处理这种情况的最好方法吗?@mjfox你把它留给语言的多态能力。您覆盖每个类型的虚拟方法,并通过从基类型调用它在循环中调用它,它将像魔术一样工作。尝试实现示例,看看它是如何实现的