为什么我们需要在 C# 中进行向上转型和向下转型?
Why do we need Upcasting & Downcasting in C#?
考虑我们有三个 classes,Shape 是基础 class 和另外两个 classes Circle 和 Text 从基础 classe 继承(形状)
Shape.cs
namespace ObjectOriented
{
public class Shape
{
public int Height { get; set; }
public int Width { get; set; }
public int X { get; set; }
public int Y { get; set; }
public void Draw()
{
}
}
}
Text.cs
using System;
namespace ObjectOriented
{
public class Text : Shape
{
public string FontType { get; set; }
public int FontSize { get; set; }
public void Weirdo()
{
Console.WriteLine("Weird stuff");
}
}
}
Circle.cs
namespace ObjectOriented
{
public class Circle : Shape
{
}
}
我们都知道向上转型总是成功的,并且我们从子class引用
创建对基class的引用
Text txt = new Text();
Shape shape = txt //upcast
向下转换可能会抛出 InvalidCastException 例如
Text txt = new Text();
Shape shape = txt; //upcast
Circle c = (Circle)shape; //DownCast InvalidCastException
我感到困惑的是,我们可能需要 up/down 转换和对象的 situations/cases 是什么?
通常,您对存储在列表中的对象使用向上转换。 (共享基类型,甚至可以使用Object
)
List<Shape> shapes = new List<Shape>();
shapes.Add((Shape)new Text()); // <-- the upcast is done automatically
shapes.Add(new Circle());
向下转型时,需要检查类型是否正确:
foreach(Shape shape in shapes)
{
if(shape is Circle)
{
Circle circle = (Circle)shape;
// do something..
}
}
一件事是,Circle
和 Text
都是 Shape
,但是您不能将 Circle
转换为 Text
。这是因为两个 classes 都扩展了 Shape
class 并添加了不同的 functionality/properties。
例如:ACar
和ABike
共享同一个基地Vihicle
(用于运送人或货物的东西,尤指在陆地上),但是 Bike
用鞍座扩展了 Vihicle
,而 Car
用例如电机扩展了车辆。因此它们不能互相 'casted' ,但两者都可以看作是 Vihicle
.
有一些有用的扩展方法,可以处理类型检查:
foreach(Circle circle in shapes.OfType<Circle>())
{
// only shapes of type Circle are iterated.
}
'Real world' 示例:
如果你有一个Window,上面有很多控件。喜欢 Labels/Buttons/ListViews/etc。所有这些控件都存储在它们的基本类型的集合中。
例如 WPF 控件:所有子控件 (在 FrameWorkElement 中) 都存储在 UIElementCollection
中。所以所有添加为子 的控件必须 来自 UIElement
.
当您迭代所有子控件 (UIElement's) 并搜索例如标签时,您必须检查它的类型:
foreach(UIElement element in this.Children)
{
if(element is Label)
{
Label myLabel = (Label)element;
myLabel.Content = "Hi there!";
}
}
此循环会将所有标签 (在此范围内) 更改为 'Hi there!'。
考虑我们有三个 classes,Shape 是基础 class 和另外两个 classes Circle 和 Text 从基础 classe 继承(形状)
Shape.cs
namespace ObjectOriented
{
public class Shape
{
public int Height { get; set; }
public int Width { get; set; }
public int X { get; set; }
public int Y { get; set; }
public void Draw()
{
}
}
}
Text.cs
using System;
namespace ObjectOriented
{
public class Text : Shape
{
public string FontType { get; set; }
public int FontSize { get; set; }
public void Weirdo()
{
Console.WriteLine("Weird stuff");
}
}
}
Circle.cs
namespace ObjectOriented
{
public class Circle : Shape
{
}
}
我们都知道向上转型总是成功的,并且我们从子class引用
创建对基class的引用Text txt = new Text();
Shape shape = txt //upcast
向下转换可能会抛出 InvalidCastException 例如
Text txt = new Text();
Shape shape = txt; //upcast
Circle c = (Circle)shape; //DownCast InvalidCastException
我感到困惑的是,我们可能需要 up/down 转换和对象的 situations/cases 是什么?
通常,您对存储在列表中的对象使用向上转换。 (共享基类型,甚至可以使用Object
)
List<Shape> shapes = new List<Shape>();
shapes.Add((Shape)new Text()); // <-- the upcast is done automatically
shapes.Add(new Circle());
向下转型时,需要检查类型是否正确:
foreach(Shape shape in shapes)
{
if(shape is Circle)
{
Circle circle = (Circle)shape;
// do something..
}
}
一件事是,Circle
和 Text
都是 Shape
,但是您不能将 Circle
转换为 Text
。这是因为两个 classes 都扩展了 Shape
class 并添加了不同的 functionality/properties。
例如:ACar
和ABike
共享同一个基地Vihicle
(用于运送人或货物的东西,尤指在陆地上),但是 Bike
用鞍座扩展了 Vihicle
,而 Car
用例如电机扩展了车辆。因此它们不能互相 'casted' ,但两者都可以看作是 Vihicle
.
有一些有用的扩展方法,可以处理类型检查:
foreach(Circle circle in shapes.OfType<Circle>())
{
// only shapes of type Circle are iterated.
}
'Real world' 示例:
如果你有一个Window,上面有很多控件。喜欢 Labels/Buttons/ListViews/etc。所有这些控件都存储在它们的基本类型的集合中。
例如 WPF 控件:所有子控件 (在 FrameWorkElement 中) 都存储在 UIElementCollection
中。所以所有添加为子 的控件必须 来自 UIElement
.
当您迭代所有子控件 (UIElement's) 并搜索例如标签时,您必须检查它的类型:
foreach(UIElement element in this.Children)
{
if(element is Label)
{
Label myLabel = (Label)element;
myLabel.Content = "Hi there!";
}
}
此循环会将所有标签 (在此范围内) 更改为 'Hi there!'。