面向对象
C#不是一种纯粹的面向对象编程语言,它提供了多种编程范式。但是,面向对象是C#的一个重要概念,也是.NET 提供的所有库的核心原则。
面向对象的三个最重要的概念是继承、封装和多态性。
本章将介绍如何使用继承增强基类型,如何创建类层次,以及C#中的多态性的工作方式。还介绍与继承相关的所有C#关键字,如何将接口用作依赖注入的契约,以及允许在接口中添加实现的默认接口方法。
类的继承
如果要声明派生自另一个类的一个类,就可以使用下面的语法:
class MyDerivedClass: MyBaseclass
{
//members
}
注意:
如果在类定义中没有指定基类,则基类将是System.Object。
下面的例子定义了基类Shape。无论是矩形还是椭圆,形状都有一些共同点:都有位置和大小。针对位置和大小,定义了相应的类,并把它们包含到Shape 类中。Shape 类定义了只读属性Position和Shape,这些属性通过自动属性初始化器来初始化
public class Position
{
public int X {get; seti }
public int Y {get; set; }
}
public class Size
{
public int Width {get; set; }
public int Height {get; seti }
}
public class Shape
{
public Position Position { get; }= new Position();
public Size Size { get; }= new Size();
}
注意:
对于形状示例,Position和Size对象包含在Shape类的一个对象中,这就是组合的概念。Rectangle和Ellipse类派生自基类Shape,这就是继承。
虚方法
把一个基类方法声明为virtual,就可以在任何派生类中重写该方法。
下面的代码片段显示的DisplayShape ( )方法在声明时使用了virtual 关键字。Shape的DrawO方法调用了这个DisplayShape0方法。虚方法可以声明为public 或 protected。在派生类中重写该方法时不能改变访问修饰符。因为Draw( )方法使用了public 访问修饰符,所以在使用Shape 或者从Shape派生
的任何类时,能够在外部使用Draw( )方法。不能重写Draw( )方法,因为它没有使用virtual 修饰符:
public class Shape
{
public void Draw()=> DisplayShape();
protected virtual void DisplayShape()
{
Console.WriteLine($"Shape with (Position} and (Size}");
}
}
也可以将属性声明为virtual。虚属性或被重写属性的语法与非虚属性相同,只不过在定义中包含一个virtual关键字:
public virtual Size Size { get; set; }
为简单起见,接下来的讨论主要关注方法,但讨论的内容也适用于属性。
声明为virtual的方法可在派生类中重写。要声明一个重写基类方法的方法,需要使用overide关键字:
public claas Rectangle : Shape
{
protected override void DisplayShape ()
{
Console.WriteLine($"Rectangle at position {Position} with size {Size}") ;
}
}
虚函数提供了OOP的一种核心特性:多态性。使用虚函数时,将调用哪个方法的决定推迟到了]运行时。编译器会创建一个虚方法表(virtual method table,vtable),其中列举了可在运行时调用的方法,然后在运行时根据类型调用方法。
出于性能考虑,在C#中,函数默认不是虚函数。对于非虚函数,不需要vtable,编译器会直接找到调用的方法。
Size 和 Position 类型重写了ToSting0方法。该方法在基类Object中被声明为virtual(代码文件:
public class Position
{
public int x {get; set;}
public int Y {get; set; }
public override string ToString( )=>$"X:{X},Y:{Y}"
}
public class Size
{
public int Width {get;set;}
public int Height {get;set;}
public override string ToString( ) =>$"Width:{Width},Height:{Height}";
}