垂头丧气


88

我是C#(和OOP)的新手。当我有如下代码时:

class Employee
{
    // some code
}


class Manager : Employee
{
    //some code
}

问题1:如果我还有其他代码可以做到这一点:

   Manager mgr = new Manager();
   Employee emp = (Employee)mgr;

Employee是一个Manager,但是当我将其像这样投射到时,Employee是否表示我要cast弃它?

问题2

当我有几个Employee类对象,而有些(但不是全部)都是时Manager,如何在可能的情况下将其转换?


6
无需显式强制转换即可完成向上转换。因此Employee emp= mgr;就足够了。
亲吻我的腋窝

Answers:


93
  1. 那是正确的。执行此操作时,会将其强制转换为employee对象,这意味着您无法访问任何特定于管理器的内容。

  2. 向下转换是您学习基础课程,然后尝试将其变成更具体的课程的地方。这可以通过使用is和如下所示的显式转换来实现:

    if (employee is Manager)
    {
        Manager m = (Manager)employee;
        //do something with it
    }
    

as像这样的运营商:

Manager m = (employee as Manager);
if (m != null)
{
    //do something with it
}

如果有任何不清楚的地方,我将很乐意纠正!


我需要示例来了解什么是垂降?
user184805

4
避免重新定义行之有效的术语:在OOP和C#的上下文中,“装箱”的含义有些不同(=将值类型对象包装到引用中)。另外,您的示例可以(并且应该)使用as运算符代替is,然后使用强制转换。
康拉德·鲁道夫

2
我在第一点上保持了正确性,并改变了答案的后半部分,以显示两种方式。
RCIX

2
您的第一个语句(“ ...将[Manager类的实例]投射到“雇员”对象[..]中意味着您无法访问任何特定于Manager的内容”)并不完全准确。在OP的示例中,如果Employee具有在Manager中被覆盖的虚拟成员,则尽管进行了强制转换,CLR仍将调用Manager实现。来自CSDN中有关多态性的MSDN文章:“当派生类重写虚拟成员时,即使将该类的实例作为基类的实例进行访问,也将调用该成员。” MSDN提供的示例几乎相同。
安东尼

49

向上转换(使用(Employee)someInstance)通常很容易,因为编译器可以在编译时告诉您类型是否从另一个类型派生。

然而,向下转换通常必须在运行时完成,因为编译器可能并不总是知道所讨论的实例是否为给定类型。C#提供了两个操作人员这一点-它告诉你,如果垂头丧气的作品,并返回真/假。而作为它试图做演员和返回正确的类型,如果可能的话,则返回null没有。

要测试员工是否是经理:

Employee m = new Manager();
Employee e = new Employee();

if(m is Manager) Console.WriteLine("m is a manager");
if(e is Manager) Console.WriteLine("e is a manager");

你也可以用这个

Employee someEmployee = e  as Manager;
    if(someEmployee  != null) Console.WriteLine("someEmployee (e) is a manager");

Employee someEmployee = m  as Manager;
    if(someEmployee  != null) Console.WriteLine("someEmployee (m) is a manager");

11
  • 向上转换是一种从子类引用创建基类引用的操作。(子类->超类)(即经理->雇员)
  • 向下转换是一种从基类引用创建子类引用的操作。(超类->子类)(即员工->经理)

就你而言

Employee emp = (Employee)mgr; //mgr is Manager

您正在上演。

与需要显式强制转换的向下转换不同,向上转换始终成功,因为向下转换在运行时可能会失败。(InvalidCastException)。

C#提供了两个运算符来避免抛出此异常:

从...开始:

Employee e = new Employee();

第一:

Manager m = e as Manager; // if downcast fails m is null; no exception thrown

第二:

if (e is Manager){...} // the predicate is false if the downcast is not possible 

警告:进行向上转换时,您只能访问超类的方法,属性等。


6

如果需要检查每个Employee对象是否都是Manager对象,请使用OfType方法:

List<Employee> employees = new List<Employee>();

//Code to add some Employee or Manager objects..

var onlyManagers = employees.OfType<Manager>();

foreach (Manager m in onlyManagers) {
  // Do Manager specific thing..
}

2

答案1:是的,它称为“向上转换”,但您的操作方式不是现代方式。可以隐式执行向上转换,无需任何转换。所以只写emp emp = mgr; 足以进行上投。

答案2:如果创建Manager类的对象,我们可以说经理是雇员。因为Manager:Employee类描述了Employee类与Manager类之间的Is-A关系。因此,我们可以说每个经理都是雇员。

但是,如果我们创建Employee类的对象,则不能说该雇员是经理,因为Employee类是不继承任何其他类的类。因此,您不能直接将该Employee Class对象转换为Manager Class对象。

因此,答案是,如果要从Employee Class对象下放到Manager Class对象,首先必须先拥有Manager Class的对象,然后才能上载它,然后再下放它。


-1

上下行:

向上转换:从派生类转换为基类向下转换:从基类转换为基类

让我们以一个例子来理解它:

将两个类Shape作为我的父类,将Circle作为派生类,定义如下:

class Shape
{
    public int Width { get; set; }
    public int Height { get; set; }
}

class Circle : Shape
{
    public int Radius { get; set; }
    public bool FillColor { get; set; }
}

上投:

Shape s = new Shape();

圈c = s;

c和s都引用相同的内存位置,但是它们都有不同的视图,即使用“ c”引用,您也可以访问基类和派生类的所有属性,但是使用“ s”引用,您可以访问属性唯一的父类。

上流的一个实际示例是Stream类,它是.net框架的所有类型的流阅读器的基类:

StreamReader reader = new StreamReader(new FileStreamReader());

在这里,FileStreamReader()向上转换为streadm reder。

下调:

Shape s = new Circle(); 如上所述,这里的s是唯一的父视图,为了使它对于父子都适用,我们需要对其进行下调

var c =(Circle)s;

向下广播的实际示例是WPF的按钮类。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.