【问题标题】:Understanding Up-casting and Down-casting c#了解向上转换和向下转换 c#
【发布时间】:2017-08-22 12:54:10
【问题描述】:

所以我试图理解 c# 中的向上转换和向下转换。

我的问题是,这张图是正确的还是我仍然遗漏了什么? 如果不正确,我在哪里可以找到正确表示这个概念的图表?

非常感谢任何帮助。

编辑: 首先,我为混乱道歉,我意识到图表不是很清楚,并且我在向下转换中犯了一个错误(其中 circle2 只能访问字符串 Colour,它应该可以访问所有属性)。 我会尝试更好地解释我想要表达的内容。

所以,下面是相应的代码:

        public class Shape 
        {
           public int Width {get;set;}
           public int Height {get;set;}
           public int X {get;set;}
           public int Y {get;set;}
           public void Draw()
           {
             //do something
           }
        }

        public class Circle : Shape 
        {
           public string Colour {get;set;}
        }
        public class Program
        {
            public static void Main(string[] args)
            {
                //Up-casting
                Circle circle = new Circle(); //object is created
                Shape shape = circle; // shape point to circle object

                //Down-casting
                Circle circle2 = (Circle)shape;
            }
        }

【问题讨论】:

  • 图表旁边的代码代表向上转换和向下转换。我不知道这些图表本身要代表什么。
  • 椭圆是否应该代表变量,即对对象的引用?
  • 方格是否代表接口,圆柱体类是否实现了这些接口?
  • 嗯,我正在努力理解更改和对象引用类型的概念。据我所知,当向上转换时,Circle 类型的圆和 Shape 类型的形状指向内存中的同一个对象/位置?并且形状和圆的所有属性都存在于该对象中。但是根据您使用的是形状还是圆形来限制对属性的访问?
  • 当涉及到这样的类时,铸造实际上并没有改变类型,它只允许你“以不同的方式看待类型”。因此,将圆形向上转换为形状不会删除 Circle 类型添加的所有属性,向下转换也不会“将它们放回原处”,它们一直存在,只是当您查看时它们隐藏在视图之外通过形状参考在圆圈处。老实说,我没看懂你的图表。

标签: c# oop


【解决方案1】:

你不需要任何图表,只要把基本的事实记下来,一切都会变得一清二楚。

上下铸造假设一个顺序,所以让我们先搞清楚:

在典型的类型层次结构中,我们有以下内容:

Animal -> Vertebrate -> Mammal -> Feline -> Cat

更高的或更一般的类型是Animal,最低的或更具体的类型是Cat;因此,顺序是类型的“一般性”。

向上转换是转换为更一般的类型,向下转换是转换为更具体的类型:

  • 向上转换:Animal animal = new Cat();
  • 向下铸造:var feline = (Feline)animal;

好的,但是在两个“演员表”中真的都在进行吗?当我们向下或向上投射时,对象会发生什么变化?答案很简单;没有什么!根本没有对对象进行任何更改。

两种转换都是引用转换,它们是保持身份的;这意味着转换之前和转换之后的对象是完全相同的对象。顾名思义,你唯一要改变的是指向对象的引用类型;变量animalcat

通过执行以下操作可以明显看出:ReferenceEquals(animal, feline); 将返回 true

注意向上转换总是隐式的,因为它总是安全Cat 始终是 Feline,而 Mammal 始终是 Mammal,等等。另一方面,向下转换必须是明确的,因为不能保证它们是安全的:

Animal animal = new Dog();
Feline feline = animal; //unsafe, can not implicitly do the conversion

编译器要求您显式执行强制转换,这是一种告诉编译器“我知道我在做什么,animalFeline,相信我。”的方式。当然,编译器只会部分信任您,并且仍会提供运行时保护以确保强制转换是可能的,如果不是,则抛出运行时异常。在上面的代码中,强制转换显然会失败,并且会出现运行时错误。

请注意,所有这些仅适用于引用类型值类型,根据定义,没有引用转换,因为您无法获得对值类型的引用。这是值类型中不允许类型变化的原因之一;没有保持身份的转换,只有类型变化中允许的转换。

【讨论】:

  • 这让我最近很吃惊,因为我没想到该对象在投射后仍然包含现在基本上隐藏的字段。例如,Cat c = new Cat(); c.VetName = "约翰史密斯";如果 Feline 没有 VetName 属性,那么 if do Feline f = c;我不再有权访问 VetName 字段,但它仍然存在!所以我可以传递猫科动物“f”对象,然后在稍后执行 Cat newCatObject = (Cat)f;然后我可以打印 newCatObject.VetName 它会打印“John Smith”。
猜你喜欢
  • 1970-01-01
  • 2017-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多