Tutorialsteacher

关注我们

文章
  • C#
  • C# 面向对象编程
  • ASP.NET Core
  • ASP.NET MVC
  • LINQ
  • 控制反转 (IoC)
  • Web API
  • JavaScript
  • TypeScript
  • jQuery
  • Angular 11
  • Node.js
  • D3.js
  • Sass
  • Python
  • Go 语言
  • HTTPS (SSL)
  • 正则表达式
  • SQL
  • SQL Server
  • PostgreSQL
  • MongoDB
  • C# - 入门
  • C# - 版本历史
  • C# - 第一个程序
  • C# - 关键词
  • C# - 类和对象
  • C# - 命名空间
  • C# - 变量
  • C# - 隐式类型变量
  • C# - 数据类型
  • 数字
  • 字符串
  • DateTime
  • 结构体
  • 枚举
  • StringBuilder
  • 匿名类型
  • 动态类型
  • 可空类型
  • C# - 值类型和引用类型
  • C# - 接口
  • C# - 运算符
  • C# - if else 语句
  • C# - 三元运算符 ?
  • C# - Switch 语句
  • C# - For 循环
  • C# - While 循环
  • C# - Do-while 循环
  • C# - 分部类
  • C# - Static 关键字
  • C# - 数组
  • 多维数组
  • 交错数组
  • C# - 索引器
  • C# - 泛型
  • 泛型约束
  • C# - 集合
  • ArrayList
  • List
  • SortedList
  • Dictionary
  • Hashtable
  • Stack
  • Queue
  • C# - 元组 (Tuple)
  • C# - 值元组 (ValueTuple)
  • C# - 内置异常
  • 异常处理
  • throw 关键字
  • 自定义异常
  • C# - 委托
  • Func 委托
  • Action 委托
  • Predicate 委托
  • 匿名方法
  • C# - 事件
  • C# - 协变
  • C# - 扩展方法
  • C# - 流 I/O
  • C# - File 类
  • C# - FileInfo 类
  • C# - 对象初始化器
  • OOP - 概述
  • 面向对象编程
  • 抽象
  • 封装
  • 关联与组合
  • 继承
  • 多态
  • 方法重写
  • 方法隐藏
  • C# - SOLID 原则
  • 单一职责原则
  • 开闭原则
  • 里氏替换原则
  • 接口隔离原则
  • 依赖倒置原则
  • 设计模式
  • 单例模式
  • 抽象工厂模式
  • 工厂方法模式
Entity Framework Extensions - 提升 EF Core 9
  批量插入
  批量删除
  批量更新
  批量合并

C# 中的继承

在面向对象编程中,继承是类之间的一种关系。继承是一种将一个类的功能重用于另一个相关类的机制。

继承被称为“是一种”关系。在现实世界的例子中,客户是一个人。同样,学生也是一个人,员工也是一个人。他们都有一些共同点,例如,他们都有名字、中间名和姓氏。因此,为了将其转换为面向对象编程,我们可以创建具有名字、中间名和姓氏属性的 Person 类,并让 Customer、Student 和 Employee 类继承自 Person 类。这样我们就无需在所有类中创建相同的属性,并避免违反 DRY(不要重复自己)原则。

请注意,继承只能用于具有共同行为且完全可替代的相关类。请遵循里氏替换原则。

Inheritance

在 C# 中,使用 : 符号来让一个类继承另一个类。例如,以下 Employee 类在 C# 中继承自 Person 类。

示例:C# 中的类继承
class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public string GetFullName(){ 
        return FirstName + " " + LastName;
    }
}

class Employee : Person
{
    public int EmployeeId { get; set; }
    public string CompanyName { get; set; }
    
}

在上面的示例中,Person 类被称为基类或父类,而 Employee 类被称为派生类或子类。

Employee 类继承自 Person 类,因此它自动获得了 Person 类的所有公共成员。这意味着即使 Employee 类不包含 FirstName、LastName 属性和 GetFullName() 方法,Employee 类的对象也将拥有 Person 类的所有属性和方法以及其自身的成员。

示例:继承的成员
Employee emp = new Employee();
emp.FirstName = "Steve";
emp.LastName = "Jobs";
emp.EmployeeId = 1;
emp.CompanyName = "Apple";

var fullname = emp.GetFullName(); //Steve Jobs
尝试一下

请注意,C# 不允许一个类继承多个类。一个类只能通过接口实现多重继承。

访问修饰符在继承中的作用

访问修饰符在继承中扮演着重要角色。基类中每个成员的访问修饰符都会影响它们在派生类中的可访问性。

公共成员

基类的公共成员在派生类中是可访问的,并且也成为派生类对象的一部分。

示例:公共成员的继承
class Person
{
    public string FirstName { get; set; } // can be inherited
}

class Employee : Person
{
        
}

Employee emp = new Employee();
emp.FirstName = "Bill"; // valid

私有成员

基类的私有成员不能直接从派生类访问,也不能成为派生类对象的一部分。

示例:私有成员的继承
class Person
{
    private string FirstName { get; set; }  // cannot be inherited
}

class Employee : Person
{
   
}

Employee emp = new Employee();
emp.FirstName; // Compile-time error

受保护成员

基类的受保护成员在派生类中是可访问的,但不能成为派生类对象的一部分。

示例:受保护成员的继承
class Person
{
    protected string FirstName { get; set; }
}

class Employee : Person
{
    public int GetName()
    {
        return this.FirstName;// valid
    }
}

Employee emp = new Employee();
emp.GetName();// valid
emp.FirstName; // Compile-time error.

内部成员

内部成员在派生类中是可访问的,并且是派生类对象的一部分。

示例:内部成员的继承
class Person
{
    internal string FirstName { get; set; } 
}

class Employee : Person
{
        
}

Employee emp = new Employee();
emp.Name= "Steve";// valid

构造函数

创建派生类对象时,会首先调用基类的构造函数,然后是派生类的构造函数。如果存在多级继承,则将首先调用第一个基类的构造函数,然后是第二个基类,依此类推。

示例:继承中的构造函数
class Person
{
    public Person()
    {
	    Console.WriteLine("Person Constructor");
	}
}

class Employee : Person
{
    public Employee()
    {
	    Console.WriteLine("Employee Constructor");
	}   
}

Employee emp = new Employee();
尝试一下
输出
Person 构造函数
Employee 构造函数

在派生类中使用 base 关键字访问基类的公共成员。例如,以下使用 :base() 调用基类的参数化构造函数。

示例:base 关键字
class Person
{
    public Person()
    {
	    Console.WriteLine("Person Constructor");
	}

    public Person(string val)
    {
	    Console.WriteLine(val);
	}
}

class Employee : Person
{
    public Employee() : base("Parameterized constructor of base class")
    {
	    Console.WriteLine("Employee Constructor");
	}   
}

Employee emp = new Employee();
尝试一下
输出
基类的参数化构造函数
Employee 构造函数

对象初始化

您可以创建派生类的实例并将其赋值给基类或派生类的变量。实例的属性和方法取决于它被赋值的变量类型。这里,类型可以是类、接口或抽象类。

下表列出了根据变量类型和实例类型支持的成员。

实例变量实例类型实例成员
基类型基类型基类型
基类型派生类型基类型
派生类型派生类型基类型和派生类型

以下程序演示了根据变量类型支持的成员

示例:对象创建
class Person
{
    public int Id { get; set; }  
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
}

class Employee : Person
{
    public string CompanyName { get; set; }
    public decimal Salary { get; set; }
}

public class Program
{
	public static void Main()
	{
        Person per1 = new Person();
        per1.Id = 1; //valid
        per1.FirstName = "James"; //valid
        per1.LastName = "Bond"; //valid

        //per1.CompanyName; // not supported
        //per1.Salary;  // not supported

        Person per2 = new Employee();
        per2.Id = 2; //valid
        per2.FirstName = "Bill"; //valid
        per2.LastName = "Gates"; //valid

        //per2.CompanyName; // not supported
        //per2.Salary;  // not supported
 
        Employee emp = new Employee();
        emp.Id = 1; //valid
        emp.FirstName = "Steve";//valid
        emp.LastName = "Jobs";//valid
        emp.CompanyName = "XYZ"; //valid
        emp.Salary = 10000; //valid 

        //invalid, can't assign base type to derived type
        //Employee emp = new Person();
     }
}
尝试一下

在上面的示例中,per2 的类型是 Person,因此即使对象类型是 Employee,它也只公开 Person 类型的公共属性。然而,emp 的类型是 Employee,因此它公开了两个类的所有公共属性。请注意,基类型对象不能赋值给派生类型变量。

类型转换

基类型隐式转换为基类,而派生类型必须使用 as 运算符显式转换为基类。

示例:从基类到派生类的类型转换
public static void Display(Employee emp){
    Console.WriteLine($"Name: {emp.FirstName} {emp.LastName}");
}

public static void Main()
{
    Person per = new Employee();
    per.FirstName="Steve";
    per.LastName="Jobs";

    //Cannot convert from Person to Employee implicitly
    Display(per);//error 

    Display(per as Employee);//valid, explicit conversion

    Employee emp = new Employee();
    emp.FirstName = "Abdul";
    emp.LastName = "Kalam";
    Display(emp);//valid
}
尝试一下
输出
员工姓名:史蒂夫·乔布斯
公司名称
员工姓名:阿卜杜勒·卡拉姆
公司名称

继承类型

C# 中支持不同类型的继承,具体取决于类的继承方式。

单一继承

在单一继承中,只有一个派生类继承一个基类。

Single Inheritance

多级继承

在多级继承中,一个派生类继承自一个基类,然后该派生类又成为另一个派生类的基类。实际上,继承的级别没有限制,但应避免过度使用。

Multi-level Inheritance

分层继承

在分层继承中,多个派生类继承自一个基类。

Hierarchical Inheritance

混合继承

混合继承是多级继承和分层继承的组合。

Multiple Inheritance

多重继承

在多重继承中,一个类继承自多个接口。请注意,C# 不支持继承多个基类。多重继承请使用接口。

Hybrid Inheritance

重要事项

  • 在 C# 中,三种类型可以参与继承:类、结构体和接口。
  • 一个类只能继承一个类。它不能继承多个类。
  • 一个类不能继承结构体。
  • 一个类可以继承(实现)一个或多个接口。
  • 一个结构体可以继承一个或多个接口。但是,它不能继承另一个结构体或类。
  • 一个接口可以继承一个或多个接口,但不能继承类或结构体。
  • 构造函数或析构函数不能被继承。
TUTORIALSTEACHER.COM

TutorialsTeacher.com 是您权威的技术教程来源,旨在通过循序渐进的方法,指导您掌握各种网络和其他技术。

我们的内容帮助所有级别的学习者轻松快速地学习技术。通过访问本平台,即表示您已阅读并同意遵守我们的使用条款和隐私政策,旨在保障您的体验和隐私权利。

[email protected]

关于我们使用条款隐私政策
copywrite-symbol

2024 TutorialsTeacher.com. (v 1.2) 版权所有。