当前位置: 首页 > news >正文

青少年编程与数学 02-020 C#程序设计基础 09课题、面向对象编程

青少年编程与数学 02-020 C#程序设计基础 09课题、面向对象编程

  • 一、概述
    • 1. 对象(Object)
    • 2. 类(Class)
    • 3. 封装(Encapsulation)
    • 4. 继承(Inheritance)
    • 5. 多态(Polymorphism)
    • 面向对象编程的优势
    • 常见的面向对象编程语言
  • 二、C#与C++比较
    • 1. 内存管理
    • 2. 语法简洁性
    • 3. 类型安全
    • 4. 异常处理
    • 5. 多继承
    • 6. 委托和事件
    • 7. 反射和动态类型
    • 8. 跨平台支持
    • 9. 性能
    • 10. 开发工具和生态系统
    • 小结
  • 三、类
    • 1. 定义类
        • 示例代码:
    • 2. 类的成员
        • 2.1 属性(Properties)
        • 2.2 方法(Methods)
        • 2.3 构造函数(Constructors)
        • 2.4 析构函数(Destructors)
        • 2.5 字段(Fields)
        • 2.6 事件(Events)
      • 3. 访问修饰符
        • 示例代码:
    • 4. 静态成员
        • 示例代码:
    • 5. 继承
        • 示例代码:
    • 6. 接口(Interfaces)
        • 示例代码:
    • 7. 抽象类(Abstract Classes)
        • 示例代码:
    • 8. 密封类(Sealed Classes)
        • 示例代码:
    • 9. 嵌套类(Nested Classes)
        • 示例代码:
    • 10. 类的实例化
        • 示例代码:
    • 小结
  • 四、类的静态成员
    • 1. 静态字段(Static Fields)
        • 示例代码:
        • 输出:
    • 2. 静态方法(Static Methods)
        • 示例代码:
        • 输出:
    • 3. 静态构造函数(Static Constructors)
        • 示例代码:
        • 输出:
    • 4. 静态属性(Static Properties)
        • 示例代码:
        • 输出:
    • 5. 静态类(Static Classes)
        • 示例代码:
        • 输出:
    • 6. 静态成员的访问规则
    • 7. 静态成员的用途
      • 小结
  • 五、对象
    • 1. 对象的创建
        • 1.1 使用 `new` 关键字
          • 示例代码:
        • 1.2 使用对象初始化器
          • 示例代码:
    • 2. 对象的使用
        • 2.1 访问属性
          • 示例代码:
        • 2.2 调用方法
          • 示例代码:
        • 2.3 对象的比较
          • 示例代码:
        • 2.4 对象的生命周期
          • 示例代码:
        • 2.5 对象的克隆
          • 示例代码:
    • 3. 对象的销毁
        • 示例代码:
    • 小结
  • 六、继承
    • 1. 继承的基本语法
        • 示例代码:
    • 2. 继承的特点
        • 2.1 代码复用
        • 2.2 扩展性
        • 2.3 多态性
    • 3. 构造函数和继承
        • 示例代码:
    • 4. 方法重写(Override)
        • 示例代码:
    • 5. 方法隐藏(Hide)
        • 示例代码:
    • 6. 抽象类和抽象方法
        • 示例代码:
    • 7. 密封类(Sealed Classes)
        • 示例代码:
    • 8. 继承的限制
      • 总结
  • 七、接口
    • 1. 接口的定义
        • 示例代码:
    • 2. 实现接口
        • 示例代码:
    • 3. 接口的特点
        • 3.1 完全抽象
        • 3.2 多继承
        • 3.3 规范行为
    • 4. 接口的使用场景
        • 4.1 定义通用行为
        • 示例代码:
        • 4.2 依赖注入
        • 示例代码:
    • 5. 接口的成员
        • 示例代码:
    • 6. 显式接口实现
        • 示例代码:
    • 7. 接口的继承
        • 示例代码:
    • 8. 接口与抽象类的区别
    • 9. 接口的默认实现(C# 8.0+)
        • 示例代码:
    • 10. 接口的使用注意事项
    • 小结
  • 八、多态
    • 1. 多态的定义
    • 2. 多态的实现方式
    • 3. 方法重写(Override)
        • 3.1 虚方法(Virtual Methods)
        • 3.2 重写方法(Override Methods)
        • 示例代码:
    • 4. 接口实现
        • 示例代码:
    • 5. 多态的优势
        • 5.1 代码复用
        • 5.2 可扩展性
        • 5.3 松耦合
    • 6. 多态的实现机制
        • 6.1 运行时多态(Runtime Polymorphism)
        • 示例代码:
        • 6.2 编译时多态(Compile-time Polymorphism)
        • 示例代码:
    • 7. 多态的使用场景
        • 7.1 通用方法
        • 示例代码:
        • 7.2 依赖注入
        • 示例代码:
    • 8. 多态的注意事项
        • 8.1 虚方法和重写方法
        • 8.2 接口实现
        • 8.3 密封类
        • 8.4 抽象类
    • 9. 多态的高级应用
        • 9.1 策略模式
        • 示例代码:
    • 小结
  • 九、综合示例
    • 代码说明
    • 输出示例
  • 总结

摘要:本文详细介绍了 C# 面向对象编程的核心概念和特性,包括类的定义、对象的创建和使用、继承、接口、多态、构造函数、析构函数、静态成员、抽象类、密封类、属性、索引器和事件等。通过丰富的代码示例,展示了如何在实际开发中应用这些特性,帮助读者更好地理解和掌握 C# 面向对象编程。

关键词:C#、面向对象编程、类、对象、继承、接口、多态、构造函数、析构函数、静态成员、抽象类、密封类、属性、索引器、事件

AI助手:Kimi、DeepSeek


一、概述

面向对象编程(Object-Oriented Programming,简称OOP)是一种编程范式,它将数据和操作数据的方法组织成对象,通过对象之间的交互来实现程序的功能。以下是面向对象编程的几个核心概念:

1. 对象(Object)

  • 定义:对象是面向对象编程中的基本单位,它封装了数据和操作数据的方法。对象可以看作是一个具有特定属性和行为的实体。
  • 示例:在现实生活中,一辆汽车可以是一个对象。它的属性包括颜色、品牌、速度等,它的行为包括启动、加速、刹车等。

2. 类(Class)

  • 定义:类是对象的模板,它定义了一组对象的共同属性和方法。类是一个抽象的概念,而对象是类的具体实例。
  • 示例:如果“汽车”是一个类,那么“红色的宝马汽车”和“蓝色的丰田汽车”就是这个类的两个实例对象。

3. 封装(Encapsulation)

  • 定义:封装是将对象的属性和方法封装在一起,隐藏对象的内部实现细节,只暴露必要的接口供外部调用。封装可以保护对象的内部状态,防止外部的非法访问。
  • 示例:在一个银行账户类中,账户余额是一个私有属性,外部代码不能直接访问和修改它,而是通过一些方法(如存款、取款)来操作余额。

4. 继承(Inheritance)

  • 定义:继承是一种代码复用的机制,它允许一个类(子类)继承另一个类(父类)的属性和方法。子类可以扩展或修改父类的行为。
  • 示例:假设有一个“动物”类,它有一些通用的属性(如名字、年龄)和方法(如吃、睡)。然后定义一个“狗”类继承“动物”类,狗类可以继承动物类的所有属性和方法,并且可以添加一些新的行为(如叫)。

5. 多态(Polymorphism)

  • 定义:多态是指同一个接口可以被不同的底层实现所使用。它允许通过父类的接口调用子类的方法,具体调用哪个子类的方法取决于实际的对象类型。
  • 示例:假设有一个“动物”类有一个“发声”方法,不同的动物(如狗、猫)继承了这个方法并实现了自己的发声方式。当调用一个动物对象的“发声”方法时,具体调用哪个发声方式取决于这个动物对象的实际类型。

面向对象编程的优势

  • 代码复用性高:通过继承和类的模板机制,可以方便地复用代码。
  • 易于维护和扩展:封装使得对象的内部实现细节隐藏,修改对象的内部实现不会影响外部调用。
  • 模拟现实世界:面向对象的思维方式更接近现实世界,便于理解和设计复杂的系统。

常见的面向对象编程语言

  • Java:一种广泛使用的面向对象编程语言,具有跨平台、安全性和强大的类库。
  • C++:一种支持面向对象编程的高级语言,同时支持过程式编程,性能高,适用于系统开发和游戏开发。
  • Python:一种简洁易读的面向对象编程语言,支持多种编程范式,具有丰富的库和框架。
  • C#:由微软开发的面向对象编程语言,主要用于Windows平台的应用开发。

面向对象编程是一种强大的编程范式,它通过对象、类、封装、继承和多态等概念,使得程序设计更加模块化、可维护和可扩展。

二、C#与C++比较

C# 和 C++ 都是面向对象编程语言,但它们在设计目标、语法细节和运行环境等方面存在显著差异。以下是 C# 面向对象编程与 C++ 面向对象编程的主要区别:

1. 内存管理

C++:

  • 手动管理:C++ 依赖程序员手动管理内存分配和释放,使用 newdelete 操作符。如果程序员忘记释放内存,可能会导致内存泄漏;如果释放了未分配的内存,可能会导致程序崩溃。
  • 智能指针:C++11 引入了智能指针(如 std::shared_ptrstd::unique_ptr),但它们的使用需要程序员显式声明和管理。
  • 示例代码:
    int* ptr = new int(10);
    delete ptr;
    

C#:

  • 自动管理:C# 使用垃圾回收机制(Garbage Collection, GC)自动管理内存。程序员不需要手动释放对象,GC 会定期检查不再使用的对象并回收它们的内存。
  • 示例代码:
    int number = 10;
    

2. 语法简洁性

C++:

  • 复杂语法:C++ 的语法较为复杂,支持多种编程范式(面向对象、过程式、泛型等),这使得代码的可读性和可维护性相对较差。
  • 模板和宏:C++ 的模板和宏功能强大,但使用不当可能导致代码难以理解和维护。
  • 示例代码:
    template <typename T>
    class MyContainer {
    public:T value;MyContainer(T val) : value(val) {}
    };
    

C#:

  • 简洁语法:C# 的语法更加简洁明了,减少了模板和宏的使用,使得代码更易于阅读和维护。
  • 示例代码:
    public class MyContainer<T>
    {public T Value { get; set; }public MyContainer(T value){Value = value;}
    }
    

3. 类型安全

C++:

  • 弱类型安全:C++ 允许隐式的类型转换,这可能导致一些难以发现的错误。
  • 示例代码:
    int a = 10;
    double b = a; // 隐式类型转换
    

C#:

  • 强类型安全:C# 严格要求类型匹配,不允许隐式的类型转换,这减少了类型错误的可能性。
  • 示例代码:
    int a = 10;
    double b = a; // 显式类型转换
    

4. 异常处理

C++:

  • 异常处理:C++ 使用 trycatchthrow 来处理异常,但异常处理机制相对复杂,且默认情况下不捕获所有异常。

  • 示例代码:

    try {throw std::runtime_error("An error occurred");
    } catch (const std::exception& e) {std::cerr << e.what() << std::endl;
    }
    

C#:

  • 完善的异常处理:C# 提供了完善的异常处理机制,所有异常都继承自 System.Exception 类,且默认情况下会捕获所有异常。
  • 示例代码:
    try {throw new Exception("An error occurred");
    } catch (Exception e) {Console.Error.WriteLine(e.Message);
    }
    

5. 多继承

C++:

  • 支持多继承:C++ 支持一个类继承多个父类,这在某些情况下非常有用,但也可能导致复杂的继承关系和潜在的二义性问题。
  • 示例代码:
    class Base1 {};
    class Base2 {};
    class Derived : public Base1, public Base2 {};
    

C#:

  • 不支持多继承:C# 不支持一个类继承多个父类,但可以通过接口来实现类似的功能。接口可以被多个类实现,从而实现多态。
  • 示例代码:
    public interface IBase1 {}
    public interface IBase2 {}
    public class Derived : IBase1, IBase2 {}
    

6. 委托和事件

C++:

  • 函数指针:C++ 使用函数指针或模板来实现回调机制,但这些机制相对复杂且不够灵活。
  • 示例代码:
    void callbackFunction() {// Callback implementation
    }void registerCallback(void (*callback)()) {// Register the callback
    }
    

C#:

  • 委托和事件:C# 提供了委托(Delegate)和事件(Event)机制,用于实现回调和事件处理,语法简洁且功能强大。
  • 示例代码:
    public delegate void MyDelegate();public class MyClass
    {public event MyDelegate MyEvent;public void TriggerEvent(){MyEvent?.Invoke();}
    }public class Program
    {public static void Main(){MyClass myClass = new MyClass();myClass.MyEvent += MyCallback;myClass.TriggerEvent();}public static void MyCallback(){Console.WriteLine("Event triggered");}
    }
    

7. 反射和动态类型

C++:

  • 有限的反射:C++ 的反射功能非常有限,主要通过模板和宏实现,但这些方法不够灵活且难以扩展。
  • 示例代码:
    template <typename T>
    void PrintType() {std::cout << typeid(T).name() << std::endl;
    }
    

C#:

  • 强大的反射:C# 提供了强大的反射机制,允许在运行时检查和操作类型、字段、方法等。此外,C# 还支持动态类型(dynamic),使得代码更加灵活。
  • 示例代码:
    using System.Reflection;public class MyClass
    {public string Name { get; set; }
    }public class Program
    {public static void Main(){MyClass myClass = new MyClass { Name = "Kimi" };Type type = myClass.GetType();PropertyInfo property = type.GetProperty("Name");Console.WriteLine(property.GetValue(myClass));}
    }
    

8. 跨平台支持

C++:

  • 跨平台:C++ 是一种跨平台语言,编写的代码可以在多种操作系统上运行,但需要针对不同的平台进行编译和优化。
  • 示例代码:
    #ifdef _WIN32
    // Windows-specific code
    #else
    // Unix-specific code
    #endif
    

C#:

  • 跨平台支持:C# 通过 .NET Core 和 .NET 5+ 提供了跨平台支持,使得 C# 程序可以在 Windows、Linux 和 macOS 上运行。此外,C# 还支持多种开发框架(如 ASP.NET Core、.NET MAUI 等)。
  • 示例代码:
    using System;public class Program
    {public static void Main(){Console.WriteLine("Hello, world!");}
    }
    

9. 性能

C++:

  • 高性能:C++ 通常比 C# 更接近硬件,因此在性能上具有优势,尤其是在需要高性能计算和低延迟的场景中。
  • 示例代码:
    int main() {int sum = 0;for (int i = 0; i < 1000000; ++i) {sum += i;}return sum;
    }
    

C#:

  • 高性能:C# 的性能也很好,但通常不如 C++。C# 的垃圾回收机制可能会引入一些性能开销,但通过优化和配置可以减少这种影响。
  • 示例代码:
    public class Program
    {public static void Main(){int sum = 0;for (int i = 0; i < 1000000; ++i) {sum += i;}Console.WriteLine(sum);}
    }
    

10. 开发工具和生态系统

C++:

  • 开发工具:C++ 有多种开发工具,如 Visual Studio、CLion、Eclipse CDT 等,但这些工具的集成度和易用性不如 C# 的开发工具。
  • 生态系统:C++ 的生态系统非常庞大,涵盖了系统编程、游戏开发、嵌入式系统等多个领域。

C#:

  • 开发工具:C# 的开发工具非常强大,尤其是 Visual Studio 和 Visual Studio Code,提供了丰富的功能和良好的集成体验。
  • 生态系统:C# 的生态系统主要集中在 Windows 开发、Web 开发、移动开发等领域,尤其是 .NET Framework 和 .NET Core 的支持。

小结

C# 和 C++ 都是强大的面向对象编程语言,但它们在内存管理、语法简洁性、类型安全、异常处理、多继承、委托和事件、反射和动态类型、跨平台支持、性能、开发工具和生态系统等方面存在显著差异。C# 更适合快速开发和维护,而 C++ 更适合高性能和底层系统开发。选择哪种语言取决于具体的项目需求和开发环境。

三、类

在 C# 中,类(Class)是面向对象编程的核心概念之一。类是对象的模板,它定义了一组对象的共同属性和方法。通过类,可以创建具体的对象实例,并通过这些实例来操作数据和执行方法。以下是对 C# 中类的详细解释:

1. 定义类

类的定义使用 class 关键字,后面跟着类的名称和类体。类体包含类的成员,如属性、方法、构造函数、析构函数等。

示例代码:
public class Person
{// 属性public string Name { get; set; }public int Age { get; set; }// 方法public void SayHello(){Console.WriteLine($"Hello, my name is {Name} and I am {Age} years old.");}// 构造函数public Person(string name, int age){Name = name;Age = age;}
}

2. 类的成员

类的成员包括属性、方法、构造函数、析构函数、字段、事件等。

2.1 属性(Properties)

属性是类的成员,用于封装类的字段,提供对字段的访问和修改。属性可以有 getset 访问器。

  • 自动实现的属性:

    public string Name { get; set; }
    
  • 手动实现的属性:

    private string name;
    public string Name
    {get { return name; }set { name = value; }
    }
    
2.2 方法(Methods)

方法是类的成员,用于定义类的行为。方法可以有参数和返回值。

  • 示例代码:
    public void SayHello()
    {Console.WriteLine($"Hello, my name is {Name} and I am {Age} years old.");
    }
    
2.3 构造函数(Constructors)

构造函数用于初始化类的实例。构造函数的名称与类名相同,没有返回值。

  • 无参构造函数:

    public Person()
    {Name = "Unknown";Age = 0;
    }
    
  • 带参构造函数:

    public Person(string name, int age)
    {Name = name;Age = age;
    }
    
2.4 析构函数(Destructors)

析构函数用于在对象被销毁时执行清理操作。析构函数的名称与类名相同,但前面加一个波浪号 ~,没有参数和返回值。

  • 示例代码:
    ~Person()
    {Console.WriteLine("Person object is being destroyed.");
    }
    
2.5 字段(Fields)

字段是类的成员变量,用于存储类的状态。

  • 示例代码:
    private string name;
    private int age;
    
2.6 事件(Events)

事件用于实现类之间的通信,通常用于观察者模式。

  • 示例代码:
    public class Button
    {public event EventHandler Click;public void OnClick(){Click?.Invoke(this, EventArgs.Empty);}
    }
    

3. 访问修饰符

C# 提供了多种访问修饰符,用于控制类成员的访问权限。

  • public:公开访问,任何地方都可以访问。
  • private:私有访问,只能在类内部访问。
  • protected:受保护访问,只能在类内部或派生类中访问。
  • internal:内部访问,只能在当前程序集内访问。
  • protected internal:受保护的内部访问,只能在当前程序集内或派生类中访问。
示例代码:
public class Person
{public string Name { get; set; }private int age;public int Age{get { return age; }set { age = value; }}protected void SayHello(){Console.WriteLine($"Hello, my name is {Name} and I am {Age} years old.");}
}

4. 静态成员

静态成员属于类本身,而不是类的某个具体实例。静态成员可以通过类名直接访问,而不需要创建类的实例。

  • 静态字段:

    public static int Count = 0;
    
  • 静态方法:

    public static void PrintCount()
    {Console.WriteLine(Count);
    }
    
示例代码:
public class Person
{public string Name { get; set; }public int Age { get; set; }public Person(string name, int age){Name = name;Age = age;Count++;}public static int Count = 0;public static void PrintCount(){Console.WriteLine(Count);}
}public class Program
{public static void Main(){Person p1 = new Person("Alice", 30);Person p2 = new Person("Bob", 25);Person.PrintCount(); // 输出 2}
}

5. 继承

C# 支持类的继承,一个类可以继承另一个类的属性和方法。继承使用 : 符号表示。

  • 基类(Base Class):

    public class Animal
    {public string Name { get; set; }public virtual void MakeSound(){Console.WriteLine("Some generic sound");}
    }
    
  • 派生类(Derived Class):

    public class Dog : Animal
    {public override void MakeSound(){Console.WriteLine("Bark");}
    }
    
示例代码:
public class Animal
{public string Name { get; set; }public virtual void MakeSound(){Console.WriteLine("Some generic sound");}
}public class Dog : Animal
{public override void MakeSound(){Console.WriteLine("Bark");}
}public class Program
{public static void Main(){Animal myDog = new Dog();myDog.Name = "Buddy";myDog.MakeSound(); // 输出 "Bark"}
}

6. 接口(Interfaces)

接口是一种完全抽象的类型,它只定义方法和属性的签名,具体的实现由实现接口的类来完成。接口用于实现多态和代码复用。

  • 定义接口:

    public interface IAnimal
    {void MakeSound();
    }
    
  • 实现接口:

    public class Dog : IAnimal
    {public void MakeSound(){Console.WriteLine("Bark");}
    }
    
示例代码:
public interface IAnimal
{void MakeSound();
}public class Dog : IAnimal
{public void MakeSound(){Console.WriteLine("Bark");}
}public class Cat : IAnimal
{public void MakeSound(){Console.WriteLine("Meow");}
}public class Program
{public static void Main(){IAnimal myDog = new Dog();myDog.MakeSound(); // 输出 "Bark"IAnimal myCat = new Cat();myCat.MakeSound(); // 输出 "Meow"}
}

7. 抽象类(Abstract Classes)

抽象类是一种不能被实例化的类,它只能被继承。抽象类可以包含抽象方法和具体方法。抽象方法没有实现,必须在派生类中实现。

  • 定义抽象类:

    public abstract class Animal
    {public abstract void MakeSound();
    }
    
  • 继承抽象类:

    public class Dog : Animal
    {public override void MakeSound(){Console.WriteLine("Bark");}
    }
    
示例代码:
public abstract class Animal
{public abstract void MakeSound();
}public class Dog : Animal
{public override void MakeSound(){Console.WriteLine("Bark");}
}public class Program
{public static void Main(){Animal myDog = new Dog();myDog.MakeSound(); // 输出 "Bark"}
}

8. 密封类(Sealed Classes)

密封类是一种不能被继承的类,使用 sealed 关键字修饰。

  • 定义密封类:
    public sealed class Person
    {public string Name { get; set; }public int Age { get; set; }
    }
    
示例代码:
public sealed class Person
{public string Name { get; set; }public int Age { get; set; }
}public class Program
{public static void Main(){Person p = new Person { Name = "Alice", Age = 30 };Console.WriteLine($"{p.Name} is {p.Age} years old.");}
}

9. 嵌套类(Nested Classes)

嵌套类是定义在另一个类内部的类。嵌套类可以访问外部类的成员,但外部类不能访问嵌套类的成员。

  • 定义嵌套类:
    public class OuterClass
    {public class NestedClass{public void PrintMessage(){Console.WriteLine("Hello from nested class");}}
    }
    
示例代码:
public class OuterClass
{public class NestedClass{public void PrintMessage(){Console.WriteLine("Hello from nested class");}}
}public class Program
{public static void Main(){OuterClass.NestedClass nested = new OuterClass.NestedClass();nested.PrintMessage(); // 输出 "Hello from nested class"}
}

10. 类的实例化

类的实例化是通过 new 关键字完成的,创建类的实例后,可以通过实例调用类的成员。

示例代码:
public class Person
{public string Name { get; set; }public int Age { get; set; }public Person(string name, int age){Name = name;Age = age;}public void SayHello(){Console.WriteLine($"Hello, my name is {Name} and I am {Age} years old.");}
}public class Program
{public static void Main(){Person p = new Person("Alice", 30);p.SayHello(); // 输出 "Hello, my name is Alice and I am 30 years old."}
}

小结

类是 C# 中面向对象编程的核心概念,它封装了数据和行为,提供了强大的功能和灵活性。通过类,可以创建对象实例,实现继承、多态、封装等面向对象的特性。掌握类的定义、成员、访问修饰符、静态成员、继承、接口、抽象类、密封类和嵌套类等概念,是理解和使用 C# 面向对象编程的基础。

四、类的静态成员

在 C# 中,类的静态成员是属于类本身而不是类的某个具体实例的成员。静态成员可以通过类名直接访问,而不需要创建类的实例。这使得静态成员在某些场景下非常有用,例如,当需要共享数据或提供全局访问点时。以下是对 C# 类的静态成员的详细解释:

1. 静态字段(Static Fields)

静态字段是属于类的字段,而不是某个实例的字段。静态字段在类加载时初始化,并且在类的整个生命周期中保持存在。

示例代码:
public class Counter
{// 静态字段public static int count = 0;// 实例字段public int instanceCount;// 构造函数public Counter(){instanceCount = ++count;}
}public class Program
{public static void Main(){Counter c1 = new Counter();Console.WriteLine($"c1.instanceCount: {c1.instanceCount}, Counter.count: {Counter.count}");Counter c2 = new Counter();Console.WriteLine($"c2.instanceCount: {c2.instanceCount}, Counter.count: {Counter.count}");}
}
输出:
c1.instanceCount: 1, Counter.count: 1
c2.instanceCount: 2, Counter.count: 2

2. 静态方法(Static Methods)

静态方法是属于类的方法,而不是某个实例的方法。静态方法可以通过类名直接调用,而不需要创建类的实例。静态方法不能访问实例成员,但可以访问静态成员。

示例代码:
public class MathUtils
{// 静态方法public static int Add(int a, int b){return a + b;}// 实例方法public int Multiply(int a, int b){return a * b;}
}public class Program
{public static void Main(){int sum = MathUtils.Add(5, 3); // 通过类名调用静态方法Console.WriteLine($"Sum: {sum}");MathUtils utils = new MathUtils();int product = utils.Multiply(5, 3); // 通过实例调用实例方法Console.WriteLine($"Product: {product}");}
}
输出:
Sum: 8
Product: 15

3. 静态构造函数(Static Constructors)

静态构造函数用于初始化类的静态成员。静态构造函数在类加载时自动调用,且只调用一次。静态构造函数没有参数,也没有返回值。

示例代码:
public class Logger
{// 静态字段public static string LogFilePath { get; private set; }// 静态构造函数static Logger(){LogFilePath = "log.txt";Console.WriteLine("Static constructor called. Log file path set to: " + LogFilePath);}// 实例方法public void Log(string message){Console.WriteLine($"Logging to {LogFilePath}: {message}");}
}public class Program
{public static void Main(){Logger logger = new Logger();logger.Log("This is a log message.");}
}
输出:
Static constructor called. Log file path set to: log.txt
Logging to log.txt: This is a log message.

4. 静态属性(Static Properties)

静态属性是属于类的属性,而不是某个实例的属性。静态属性可以通过类名直接访问,而不需要创建类的实例。静态属性可以有 getset 访问器。

示例代码:
public class Settings
{// 静态字段private static string _theme = "Light";// 静态属性public static string Theme{get { return _theme; }set { _theme = value; }}
}public class Program
{public static void Main(){Console.WriteLine($"Current theme: {Settings.Theme}");Settings.Theme = "Dark";Console.WriteLine($"New theme: {Settings.Theme}");}
}
输出:
Current theme: Light
New theme: Dark

5. 静态类(Static Classes)

静态类是一种特殊的类,它只能包含静态成员,并且不能被实例化。静态类通常用于提供一组工具方法或常量。

示例代码:
public static class MathUtils
{public static int Add(int a, int b){return a + b;}public static int Multiply(int a, int b){return a * b;}
}public class Program
{public static void Main(){int sum = MathUtils.Add(5, 3);Console.WriteLine($"Sum: {sum}");int product = MathUtils.Multiply(5, 3);Console.WriteLine($"Product: {product}");}
}
输出:
Sum: 8
Product: 15

6. 静态成员的访问规则

  • 静态成员属于类本身:静态成员可以通过类名直接访问,而不需要创建类的实例。
  • 静态成员不能访问实例成员:静态方法和静态属性不能访问实例字段和实例方法,因为实例成员需要具体的实例才能访问。
  • 静态成员在类加载时初始化:静态字段和静态构造函数在类加载时自动初始化,且只初始化一次。

7. 静态成员的用途

  • 共享数据:静态字段可以用于在类的所有实例之间共享数据。
  • 工具类:静态方法和静态类常用于提供工具方法,这些方法不需要依赖类的实例。
  • 全局访问点:静态成员可以提供全局访问点,例如单例模式中的静态实例。

小结

静态成员是 C# 中类的重要组成部分,它们提供了在类级别共享数据和行为的能力。通过静态字段、静态方法、静态构造函数、静态属性和静态类,可以实现多种功能,如共享数据、工具方法、全局访问点等。掌握静态成员的定义、访问规则和用途,是理解和使用 C# 面向对象编程的重要部分。

五、对象

在 C# 中,对象是类的实例,通过对象可以访问类的属性和方法。对象的创建和使用是面向对象编程的核心内容。以下是对 C# 中对象的创建和使用的详细解释:

1. 对象的创建

1.1 使用 new 关键字

在 C# 中,对象的创建通常使用 new 关键字。new 关键字会调用类的构造函数来初始化对象。

示例代码:
public class Person
{public string Name { get; set; }public int Age { get; set; }// 无参构造函数public Person(){Name = "Unknown";Age = 0;}// 带参构造函数public Person(string name, int age){Name = name;Age = age;}public void SayHello(){Console.WriteLine($"Hello, my name is {Name} and I am {Age} years old.");}
}public class Program
{public static void Main(){// 使用无参构造函数创建对象Person person1 = new Person();person1.Name = "Alice";person1.Age = 30;person1.SayHello(); // 输出 "Hello, my name is Alice and I am 30 years old."// 使用带参构造函数创建对象Person person2 = new Person("Bob", 25);person2.SayHello(); // 输出 "Hello, my name is Bob and I am 25 years old."}
}
1.2 使用对象初始化器

C# 提供了对象初始化器语法,可以在创建对象时直接初始化属性,而不需要显式调用构造函数。

示例代码:
public class Person
{public string Name { get; set; }public int Age { get; set; }public void SayHello(){Console.WriteLine($"Hello, my name is {Name} and I am {Age} years old.");}
}public class Program
{public static void Main(){// 使用对象初始化器创建对象Person person1 = new Person { Name = "Alice", Age = 30 };person1.SayHello(); // 输出 "Hello, my name is Alice and I am 30 years old."// 如果类有带参构造函数,也可以结合使用Person person2 = new Person("Bob", 25) { Name = "Robert" };person2.SayHello(); // 输出 "Hello, my name is Robert and I am 25 years old."}
}

2. 对象的使用

2.1 访问属性

通过对象可以访问类的属性。属性可以是只读的(get),也可以是可读写的(getset)。

示例代码:
public class Person
{public string Name { get; set; }public int Age { get; set; }
}public class Program
{public static void Main(){Person person = new Person { Name = "Alice", Age = 30 };// 访问属性Console.WriteLine(person.Name); // 输出 "Alice"Console.WriteLine(person.Age);  // 输出 30// 修改属性person.Name = "Alicia";person.Age = 31;Console.WriteLine(person.Name); // 输出 "Alicia"Console.WriteLine(person.Age);  // 输出 31}
}
2.2 调用方法

通过对象可以调用类的方法。方法可以有参数,也可以返回值。

示例代码:
public class Person
{public string Name { get; set; }public int Age { get; set; }public void SayHello(){Console.WriteLine($"Hello, my name is {Name} and I am {Age} years old.");}public int GetAgeInMonths(){return Age * 12;}
}public class Program
{public static void Main(){Person person = new Person { Name = "Alice", Age = 30 };// 调用方法person.SayHello(); // 输出 "Hello, my name is Alice and I am 30 years old."// 调用有返回值的方法int ageInMonths = person.GetAgeInMonths();Console.WriteLine($"Age in months: {ageInMonths}"); // 输出 "Age in months: 360"}
}
2.3 对象的比较

C# 提供了多种方式来比较对象,包括引用比较和值比较。

示例代码:
public class Person
{public string Name { get; set; }public int Age { get; set; }
}public class Program
{public static void Main(){Person person1 = new Person { Name = "Alice", Age = 30 };Person person2 = new Person { Name = "Alice", Age = 30 };Person person3 = person1;// 引用比较Console.WriteLine(person1 == person2); // 输出 "False",因为 person1 和 person2 是不同的实例Console.WriteLine(person1 == person3); // 输出 "True",因为 person1 和 person3 指向同一个实例// 值比较Console.WriteLine(person1.Name == person2.Name); // 输出 "True"Console.WriteLine(person1.Age == person2.Age);   // 输出 "True"}
}
2.4 对象的生命周期

对象的生命周期从创建开始,到垃圾回收结束。C# 使用垃圾回收机制(GC)自动管理对象的内存。

示例代码:
public class Person
{public string Name { get; set; }public int Age { get; set; }public Person(string name, int age){Name = name;Age = age;}// 析构函数~Person(){Console.WriteLine($"{Name} is being garbage collected.");}
}public class Program
{public static void Main(){Person person = new Person("Alice", 30);person = null; // 使对象失去引用,等待垃圾回收// 强制垃圾回收GC.Collect();}
}
2.5 对象的克隆

C# 提供了克隆机制,可以通过 ICloneable 接口或手动实现克隆方法来创建对象的副本。

示例代码:
using System;public class Person : ICloneable
{public string Name { get; set; }public int Age { get; set; }public Person(string name, int age){Name = name;Age = age;}public object Clone(){return new Person(Name, Age);}
}public class Program
{public static void Main(){Person person1 = new Person("Alice", 30);Person person2 = (Person)person1.Clone();Console.WriteLine(person1 == person2); // 输出 "False",因为 person1 和 person2 是不同的实例Console.WriteLine(person1.Name == person2.Name); // 输出 "True"Console.WriteLine(person1.Age == person2.Age);   // 输出 "True"}
}

3. 对象的销毁

C# 使用垃圾回收机制(GC)自动管理对象的销毁。当对象不再被任何引用指向时,GC 会自动回收其内存。

示例代码:
public class Person
{public string Name { get; set; }public int Age { get; set; }public Person(string name, int age){Name = name;Age = age;}// 析构函数~Person(){Console.WriteLine($"{Name} is being garbage collected.");}
}public class Program
{public static void Main(){Person person = new Person("Alice", 30);person = null; // 使对象失去引用,等待垃圾回收// 强制垃圾回收GC.Collect();}
}

小结

在 C# 中,对象的创建和使用是面向对象编程的基础。通过 new 关键字和对象初始化器可以创建对象,通过对象可以访问类的属性和方法。对象的生命周期由垃圾回收机制管理,可以通过克隆机制创建对象的副本。掌握对象的创建、使用、比较、生命周期和销毁,是理解和使用 C# 面向对象编程的重要部分。

六、继承

在 C# 中,继承是面向对象编程的核心特性之一,它允许一个类(称为派生类或子类)继承另一个类(称为基类或父类)的属性和方法。通过继承,可以实现代码复用,提高开发效率,并且可以构建出层次化的类结构。以下是对 C# 中继承的详细解释:

1. 继承的基本语法

在 C# 中,继承使用 : 符号表示。派生类可以继承基类的属性和方法,但不能继承基类的构造函数和析构函数。

示例代码:
public class Animal
{public string Name { get; set; }public Animal(string name){Name = name;}public virtual void MakeSound(){Console.WriteLine("Some generic sound");}
}public class Dog : Animal
{public Dog(string name) : base(name) // 调用基类的构造函数{}public override void MakeSound(){Console.WriteLine("Bark");}
}public class Cat : Animal
{public Cat(string name) : base(name){}public override void MakeSound(){Console.WriteLine("Meow");}
}public class Program
{public static void Main(){Animal myDog = new Dog("Buddy");myDog.MakeSound(); // 输出 "Bark"Animal myCat = new Cat("Whiskers");myCat.MakeSound(); // 输出 "Meow"}
}

2. 继承的特点

2.1 代码复用

派生类继承了基类的属性和方法,减少了重复代码的编写。

2.2 扩展性

派生类可以扩展基类的功能,通过添加新的属性和方法,或者重写基类的方法来实现特定的行为。

2.3 多态性

继承是实现多态的基础。通过基类的引用可以调用派生类的方法,具体调用哪个方法取决于实际的对象类型。

3. 构造函数和继承

派生类的构造函数可以调用基类的构造函数来初始化基类的成员。这通过 base 关键字实现。

示例代码:
public class Animal
{public string Name { get; set; }public Animal(string name){Name = name;}
}public class Dog : Animal
{public Dog(string name) : base(name) // 调用基类的构造函数{}
}public class Program
{public static void Main(){Dog myDog = new Dog("Buddy");Console.WriteLine(myDog.Name); // 输出 "Buddy"}
}

4. 方法重写(Override)

派生类可以重写基类中的虚方法(使用 virtual 关键字声明的方法)。重写方法使用 override 关键字。

示例代码:
public class Animal
{public virtual void MakeSound(){Console.WriteLine("Some generic sound");}
}public class Dog : Animal
{public override void MakeSound(){Console.WriteLine("Bark");}
}public class Program
{public static void Main(){Animal myDog = new Dog();myDog.MakeSound(); // 输出 "Bark"}
}

5. 方法隐藏(Hide)

如果派生类中定义了一个与基类同名的方法,但没有使用 override 关键字,那么派生类的方法会隐藏基类的方法。这称为方法隐藏,使用 new 关键字显式表示。

示例代码:
public class Animal
{public void MakeSound(){Console.WriteLine("Some generic sound");}
}public class Dog : Animal
{public new void MakeSound(){Console.WriteLine("Bark");}
}public class Program
{public static void Main(){Animal myDog = new Dog();myDog.MakeSound(); // 输出 "Some generic sound"Dog myDog2 = new Dog();myDog2.MakeSound(); // 输出 "Bark"}
}

6. 抽象类和抽象方法

抽象类是不能被实例化的类,它只能被继承。抽象类可以包含抽象方法(使用 abstract 关键字声明的方法),这些方法没有实现,必须在派生类中实现。

示例代码:
public abstract class Animal
{public abstract void MakeSound();
}public class Dog : Animal
{public override void MakeSound(){Console.WriteLine("Bark");}
}public class Program
{public static void Main(){Animal myDog = new Dog();myDog.MakeSound(); // 输出 "Bark"}
}

7. 密封类(Sealed Classes)

密封类是不能被继承的类,使用 sealed 关键字修饰。

示例代码:
public sealed class Person
{public string Name { get; set; }public int Age { get; set; }
}public class Program
{public static void Main(){Person person = new Person { Name = "Alice", Age = 30 };Console.WriteLine($"{person.Name} is {person.Age} years old.");}
}

8. 继承的限制

  • C# 不支持多重继承:一个类只能继承一个基类,但可以通过接口实现类似的功能。
  • 基类的构造函数必须被调用:派生类的构造函数必须显式或隐式调用基类的构造函数。
  • 抽象类不能被实例化:抽象类只能被继承,不能直接创建实例。
  • 密封类不能被继承:密封类不能有派生类。

总结

继承是 C# 面向对象编程中的一个重要特性,它允许派生类继承基类的属性和方法,实现代码复用和扩展性。通过方法重写和多态性,可以实现灵活的类设计。掌握继承的基本语法、构造函数的调用、方法重写、抽象类、密封类和接口的使用,是理解和使用 C# 面向对象编程的关键部分。

七、接口

在 C# 中,接口(Interface)是一种完全抽象的类型,它定义了一组方法、属性、索引器和事件的签名,但不提供具体的实现。接口的主要作用是规范实现类的行为,确保实现类提供接口中定义的所有成员的实现。接口是实现多态和代码复用的重要机制。以下是对 C# 中接口的详细解释:

1. 接口的定义

接口使用 interface 关键字定义。接口中的成员(方法、属性、索引器和事件)默认是 public 的,不能有访问修饰符,并且不能有实现。

示例代码:
public interface IAnimal
{void MakeSound(); // 方法签名string Name { get; set; } // 属性签名event EventHandler OnSound; // 事件签名
}

2. 实现接口

类可以通过 : 符号实现接口,并提供接口中定义的所有成员的具体实现。

示例代码:
public class Dog : IAnimal
{public string Name { get; set; }public void MakeSound(){Console.WriteLine("Bark");}public event EventHandler OnSound;protected virtual void OnMakeSound(EventArgs e){OnSound?.Invoke(this, e);}
}public class Cat : IAnimal
{public string Name { get; set; }public void MakeSound(){Console.WriteLine("Meow");}public event EventHandler OnSound;protected virtual void OnMakeSound(EventArgs e){OnSound?.Invoke(this, e);}
}

3. 接口的特点

3.1 完全抽象

接口中的成员没有实现,具体的实现由实现接口的类提供。

3.2 多继承

C# 不支持多重继承,但一个类可以实现多个接口,从而实现类似多重继承的功能。

3.3 规范行为

接口的主要作用是规范实现类的行为,确保实现类提供接口中定义的所有成员的实现。

4. 接口的使用场景

4.1 定义通用行为

接口可以定义一组通用的行为,多个类可以实现这些行为,从而实现多态。

示例代码:
public interface IAnimal
{void MakeSound();
}public class Dog : IAnimal
{public void MakeSound(){Console.WriteLine("Bark");}
}public class Cat : IAnimal
{public void MakeSound(){Console.WriteLine("Meow");}
}public class Program
{public static void Main(){IAnimal myDog = new Dog();myDog.MakeSound(); // 输出 "Bark"IAnimal myCat = new Cat();myCat.MakeSound(); // 输出 "Meow"}
}
4.2 依赖注入

接口常用于依赖注入,通过接口可以实现松耦合的设计,使得代码更容易测试和维护。

示例代码:
public interface IAnimal
{void MakeSound();
}public class Dog : IAnimal
{public void MakeSound(){Console.WriteLine("Bark");}
}public class AnimalSoundMaker
{private IAnimal animal;public AnimalSoundMaker(IAnimal animal){this.animal = animal;}public void MakeSound(){animal.MakeSound();}
}public class Program
{public static void Main(){IAnimal myDog = new Dog();AnimalSoundMaker soundMaker = new AnimalSoundMaker(myDog);soundMaker.MakeSound(); // 输出 "Bark"}
}

5. 接口的成员

接口可以包含以下类型的成员:

  • 方法:定义方法的签名。
  • 属性:定义属性的签名。
  • 索引器:定义索引器的签名。
  • 事件:定义事件的签名。
示例代码:
public interface IAnimal
{void MakeSound(); // 方法签名string Name { get; set; } // 属性签名string this[int index] { get; set; } // 索引器签名event EventHandler OnSound; // 事件签名
}

6. 显式接口实现

类可以显式实现接口的成员,这样实现的成员只能通过接口类型的引用访问,而不能通过类类型的引用访问。

示例代码:
public interface IAnimal
{void MakeSound();
}public class Dog : IAnimal
{void IAnimal.MakeSound(){Console.WriteLine("Bark");}
}public class Program
{public static void Main(){Dog myDog = new Dog();// myDog.MakeSound(); // 错误:Dog 类中没有 MakeSound 方法IAnimal animal = myDog;animal.MakeSound(); // 输出 "Bark"}
}

7. 接口的继承

接口可以继承其他接口,从而扩展接口的功能。

示例代码:
public interface IAnimal
{void MakeSound();
}public interface IDomesticAnimal : IAnimal
{void GreetOwner();
}public class Dog : IDomesticAnimal
{public void MakeSound(){Console.WriteLine("Bark");}public void GreetOwner(){Console.WriteLine("Wag tail");}
}public class Program
{public static void Main(){Dog myDog = new Dog();myDog.MakeSound(); // 输出 "Bark"myDog.GreetOwner(); // 输出 "Wag tail"}
}

8. 接口与抽象类的区别

  • 接口:

    • 完全抽象,不能有实现。
    • 可以包含方法、属性、索引器和事件的签名。
    • 一个类可以实现多个接口。
    • 用于规范行为,实现多态。
  • 抽象类:

    • 可以包含抽象方法和具体方法。
    • 可以包含字段和属性。
    • 一个类只能继承一个抽象类。
    • 用于提供默认实现,实现代码复用。

9. 接口的默认实现(C# 8.0+)

从 C# 8.0 开始,接口可以提供默认实现。这使得接口不仅可以定义行为,还可以提供默认的实现,从而减少重复代码。

示例代码:
public interface IAnimal
{void MakeSound(){Console.WriteLine("Some generic sound");}
}public class Dog : IAnimal
{public void MakeSound(){Console.WriteLine("Bark");}
}public class Cat : IAnimal
{// 使用接口的默认实现
}public class Program
{public static void Main(){IAnimal myDog = new Dog();myDog.MakeSound(); // 输出 "Bark"IAnimal myCat = new Cat();myCat.MakeSound(); // 输出 "Some generic sound"}
}

10. 接口的使用注意事项

  • 接口的成员默认是 public 的,不能有访问修饰符。
  • 接口不能包含字段。
  • 接口不能有构造函数和析构函数。
  • 接口的成员可以有默认实现,但实现类可以选择重写这些方法。

小结

接口是 C# 中实现多态和代码复用的重要机制。通过接口,可以定义一组通用的行为,多个类可以实现这些行为,从而实现多态。接口的主要作用是规范实现类的行为,确保实现类提供接口中定义的所有成员的实现。掌握接口的定义、实现、成员、显式实现、继承和默认实现,是理解和使用 C# 面向对象编程的重要部分。

八、多态

在 C# 中,多态(Polymorphism)是面向对象编程的核心特性之一,它允许通过基类的引用调用派生类的方法,具体调用哪个方法取决于实际的对象类型。多态使得程序更加灵活和可扩展,能够以统一的方式处理不同类型的对象。以下是对 C# 中多态的详细解释:

1. 多态的定义

多态是指同一个接口可以被不同的底层实现所使用。具体来说,多态允许通过基类的引用调用派生类的方法,具体调用哪个方法取决于实际的对象类型。

2. 多态的实现方式

在 C# 中,多态主要通过以下两种方式实现:

  • 方法重写(Override)
  • 接口实现

3. 方法重写(Override)

3.1 虚方法(Virtual Methods)

虚方法是使用 virtual 关键字声明的方法,可以在派生类中被重写。

3.2 重写方法(Override Methods)

派生类使用 override 关键字重写基类中的虚方法。

示例代码:
public class Animal
{public virtual void MakeSound(){Console.WriteLine("Some generic sound");}
}public class Dog : Animal
{public override void MakeSound(){Console.WriteLine("Bark");}
}public class Cat : Animal
{public override void MakeSound(){Console.WriteLine("Meow");}
}public class Program
{public static void Main(){Animal myDog = new Dog();myDog.MakeSound(); // 输出 "Bark"Animal myCat = new Cat();myCat.MakeSound(); // 输出 "Meow"}
}

4. 接口实现

接口是一种完全抽象的类型,它定义了一组方法、属性、索引器和事件的签名,但不提供具体的实现。通过接口实现,可以实现多态。

示例代码:
public interface IAnimal
{void MakeSound();
}public class Dog : IAnimal
{public void MakeSound(){Console.WriteLine("Bark");}
}public class Cat : IAnimal
{public void MakeSound(){Console.WriteLine("Meow");}
}public class Program
{public static void Main(){IAnimal myDog = new Dog();myDog.MakeSound(); // 输出 "Bark"IAnimal myCat = new Cat();myCat.MakeSound(); // 输出 "Meow"}
}

5. 多态的优势

5.1 代码复用

通过多态,可以编写通用的代码,减少重复代码的编写。

5.2 可扩展性

多态使得程序更加灵活,可以方便地添加新的类,而不需要修改现有代码。

5.3 松耦合

多态使得类之间的耦合度降低,提高了代码的可维护性和可测试性。

6. 多态的实现机制

6.1 运行时多态(Runtime Polymorphism)

运行时多态是指在运行时根据对象的实际类型调用相应的方法。这是通过虚方法和重写方法实现的。

示例代码:
public class Animal
{public virtual void MakeSound(){Console.WriteLine("Some generic sound");}
}public class Dog : Animal
{public override void MakeSound(){Console.WriteLine("Bark");}
}public class Program
{public static void Main(){Animal myDog = new Dog();myDog.MakeSound(); // 输出 "Bark"}
}
6.2 编译时多态(Compile-time Polymorphism)

编译时多态是指在编译时根据方法的签名调用相应的方法。这是通过方法重载实现的。

示例代码:
public class MathUtils
{public int Add(int a, int b){return a + b;}public double Add(double a, double b){return a + b;}
}public class Program
{public static void Main(){MathUtils utils = new MathUtils();int sum1 = utils.Add(5, 3); // 调用 int 版本的 Add 方法double sum2 = utils.Add(5.5, 3.3); // 调用 double 版本的 Add 方法Console.WriteLine($"Sum1: {sum1}"); // 输出 "Sum1: 8"Console.WriteLine($"Sum2: {sum2}"); // 输出 "Sum2: 8.8"}
}

7. 多态的使用场景

7.1 通用方法

通过基类或接口的引用,可以编写通用的方法,这些方法可以处理不同类型的对象。

示例代码:
public class Animal
{public virtual void MakeSound(){Console.WriteLine("Some generic sound");}
}public class Dog : Animal
{public override void MakeSound(){Console.WriteLine("Bark");}
}public class Cat : Animal
{public override void MakeSound(){Console.WriteLine("Meow");}
}public class Program
{public static void MakeAnimalSound(Animal animal){animal.MakeSound();}public static void Main(){Dog myDog = new Dog();Cat myCat = new Cat();MakeAnimalSound(myDog); // 输出 "Bark"MakeAnimalSound(myCat); // 输出 "Meow"}
}
7.2 依赖注入

通过接口或基类的引用,可以实现依赖注入,使得代码更加灵活和可测试。

示例代码:
public interface IAnimal
{void MakeSound();
}public class Dog : IAnimal
{public void MakeSound(){Console.WriteLine("Bark");}
}public class Cat : IAnimal
{public void MakeSound(){Console.WriteLine("Meow");}
}public class AnimalSoundMaker
{private IAnimal animal;public AnimalSoundMaker(IAnimal animal){this.animal = animal;}public void MakeSound(){animal.MakeSound();}
}public class Program
{public static void Main(){IAnimal myDog = new Dog();AnimalSoundMaker soundMaker = new AnimalSoundMaker(myDog);soundMaker.MakeSound(); // 输出 "Bark"}
}

8. 多态的注意事项

8.1 虚方法和重写方法

虚方法使用 virtual 关键字声明,重写方法使用 override 关键字声明。

8.2 接口实现

接口中的成员默认是 public 的,不能有访问修饰符。

8.3 密封类

密封类(sealed)不能被继承,因此不能在密封类中使用虚方法。

8.4 抽象类

抽象类可以包含虚方法和抽象方法,派生类必须实现抽象方法。

9. 多态的高级应用

9.1 策略模式

策略模式是一种行为设计模式,通过定义一系列算法,并将每个算法封装起来,使它们可以互换使用。策略模式利用了多态的特性。

示例代码:
public interface IStrategy
{void Execute(int a, int b);
}public class AddStrategy : IStrategy
{public void Execute(int a, int b){Console.WriteLine($"Result: {a + b}");}
}public class SubtractStrategy : IStrategy
{public void Execute(int a, int b){Console.WriteLine($"Result: {a - b}");}
}public class Context
{private IStrategy strategy;public Context(IStrategy strategy){this.strategy = strategy;}public void SetStrategy(IStrategy strategy){this.strategy = strategy;}public void ExecuteStrategy(int a, int b){strategy.Execute(a, b);}
}public class Program
{public static void Main(){IStrategy addStrategy = new AddStrategy();IStrategy subtractStrategy = new SubtractStrategy();Context context = new Context(addStrategy);context.ExecuteStrategy(10, 5); // 输出 "Result: 15"context.SetStrategy(subtractStrategy);context.ExecuteStrategy(10, 5); // 输出 "Result: 5"}
}

小结

多态是 C# 面向对象编程中的一个重要特性,它允许通过基类的引用调用派生类的方法,具体调用哪个方法取决于实际的对象类型。多态主要通过方法重写和接口实现来实现,具有代码复用、可扩展性和松耦合等优势。掌握多态的实现方式、使用场景和高级应用,是理解和使用 C# 面向对象编程的关键部分。

九、综合示例

以下是一个综合示例代码,全面展示了 C# 面向对象编程的各种相关特性,包括类的定义、对象的创建和使用、继承、接口、多态、构造函数、析构函数、静态成员、抽象类、密封类、属性、索引器、事件等:

using System;// 定义一个接口
public interface IAnimal
{void MakeSound();string Name { get; set; }
}// 定义一个抽象类
public abstract class Animal : IAnimal
{public string Name { get; set; }public Animal(string name){Name = name;}public abstract void MakeSound();// 静态字段public static int AnimalCount { get; private set; } = 0;// 构造函数public Animal(){AnimalCount++;}// 析构函数~Animal(){AnimalCount--;Console.WriteLine($"{Name} is being destroyed. Remaining animals: {AnimalCount}");}// 事件public event EventHandler OnSound;protected virtual void OnMakeSound(EventArgs e){OnSound?.Invoke(this, e);}
}// 定义一个派生类
public class Dog : Animal
{public Dog(string name) : base(name){}public override void MakeSound(){Console.WriteLine("Bark");OnMakeSound(EventArgs.Empty);}
}// 定义另一个派生类
public class Cat : Animal
{public Cat(string name) : base(name){}public override void MakeSound(){Console.WriteLine("Meow");OnMakeSound(EventArgs.Empty);}
}// 定义一个密封类
public sealed class Bulldog : Dog
{public Bulldog(string name) : base(name){}public new void MakeSound(){Console.WriteLine("Woof");}
}// 定义一个类实现接口
public class Duck : IAnimal
{public string Name { get; set; }public Duck(string name){Name = name;}public void MakeSound(){Console.WriteLine("Quack");}
}// 定义一个类使用接口
public class AnimalSoundMaker
{private IAnimal animal;public AnimalSoundMaker(IAnimal animal){this.animal = animal;}public void MakeSound(){animal.MakeSound();}
}public class Program
{public static void Main(){// 创建对象IAnimal dog = new Dog("Buddy");IAnimal cat = new Cat("Whiskers");IAnimal duck = new Duck("Donald");// 调用方法dog.MakeSound(); // 输出 "Bark"cat.MakeSound(); // 输出 "Meow"duck.MakeSound(); // 输出 "Quack"// 使用 AnimalSoundMaker 类AnimalSoundMaker soundMaker = new AnimalSoundMaker(dog);soundMaker.MakeSound(); // 输出 "Bark"soundMaker = new AnimalSoundMaker(cat);soundMaker.MakeSound(); // 输出 "Meow"// 静态成员Console.WriteLine($"Total animals: {Animal.AnimalCount}"); // 输出 "Total animals: 3"// 密封类Bulldog bulldog = new Bulldog("Spike");bulldog.MakeSound(); // 输出 "Woof"// 事件dog.OnSound += (sender, e) => Console.WriteLine($"{((Animal)sender).Name} made a sound.");dog.MakeSound(); // 输出 "Bark" 和 "Buddy made a sound."// 对象销毁dog = null;cat = null;duck = null;bulldog = null;// 强制垃圾回收GC.Collect();}
}

代码说明

  1. 接口(IAnimal):

    • 定义了 MakeSound 方法和 Name 属性的签名。
    • Duck 类实现了 IAnimal 接口。
  2. 抽象类(Animal):

    • 定义了 MakeSound 抽象方法和 Name 属性。
    • 包含静态字段 AnimalCount,用于统计动物的数量。
    • 包含构造函数和析构函数,用于管理对象的生命周期。
    • 包含事件 OnSound,用于通知其他对象动物发声。
  3. 派生类(DogCat):

    • 继承自 Animal 类,并重写了 MakeSound 方法。
    • 调用了基类的构造函数。
  4. 密封类(Bulldog):

    • 继承自 Dog 类,但被声明为密封类,不能被进一步继承。
    • 重写了 MakeSound 方法。
  5. 类实现接口(Duck):

    • 实现了 IAnimal 接口,提供了 MakeSound 方法和 Name 属性的具体实现。
  6. 类使用接口(AnimalSoundMaker):

    • 通过依赖注入,使用 IAnimal 接口的引用调用 MakeSound 方法。
  7. 多态:

    • 通过基类的引用调用派生类的方法,具体调用哪个方法取决于实际的对象类型。
  8. 静态成员:

    • AnimalCount 是一个静态字段,用于统计动物的数量。
  9. 事件:

    • OnSound 是一个事件,用于通知其他对象动物发声。
  10. 对象销毁:

    • 通过将对象引用设置为 null,使对象失去引用,等待垃圾回收。
    • 调用 GC.Collect() 强制垃圾回收。

输出示例

运行上述代码,输出可能如下:

Bark
Meow
Quack
Bark
Meow
Total animals: 3
Woof
Bark
Buddy made a sound.
Whiskers is being destroyed. Remaining animals: 2
Donald is being destroyed. Remaining animals: 1
Buddy is being destroyed. Remaining animals: 0
Spike is being destroyed. Remaining animals: 0

这个示例代码展示了 C# 面向对象编程的多种特性,包括类的定义、对象的创建和使用、继承、接口、多态、构造函数、析构函数、静态成员、抽象类、密封类、属性、索引器和事件等。通过这个示例,可以更好地理解和掌握 C# 面向对象编程的核心概念。

总结

本文全面介绍了 C# 面向对象编程的核心概念和特性,包括类的定义、对象的创建和使用、继承、接口、多态、构造函数、析构函数、静态成员、抽象类、密封类、属性、索引器和事件等。通过详细的代码示例,展示了如何在实际开发中应用这些特性。类是面向对象编程的基础,通过类可以创建对象实例,实现封装、继承和多态等特性。接口和抽象类用于规范行为,实现多态和代码复用。静态成员和密封类提供了全局访问点和不可继承的特性。多态通过方法重写和接口实现,使得程序更加灵活和可扩展。通过综合示例代码,读者可以更好地理解和掌握这些概念,提升面向对象编程的能力。

相关文章:

  • IO 中的阻塞、非阻塞、同步、异步及五种IO模型
  • 如何更新和清理 Go 依赖版本
  • flutter使用html_editor_enhanced: ^2.6.0后,编辑框无法获取焦点,无法操作
  • 4.8.4 利用Spark SQL实现分组排行榜
  • 2021年认证杯SPSSPRO杯数学建模D题(第二阶段)停车的策略全过程文档及程序
  • 手机如何压缩文件为 RAR 格式:详细教程与工具推荐
  • python:selenium爬取网站信息
  • 华为手机用的时间长了,提示手机电池性能下降,需要去换电池吗?平时要怎么用能让电池寿命长久一些?
  • 8卡910B4-32G测试Qwen2.5-VL-72B-instruct模型兼容性
  • 什么是数字化转型,如何系统性重构业务逻辑
  • SD-WAN 与传统网络方案组合应用:降本增效的政务网建设新策略
  • mac 下安装Rust Toolchain(Nightly)
  • CORS跨域资源共享解析
  • EFcore8和Sql Server 2014冲突
  • WebAssembly 及 HTML Streaming:重塑前端性能与用户体验
  • 【Doris基础】Apache Doris 基本架构深度解析:从存储到查询的完整技术演进
  • 无人机分布式协同算法解析!
  • 考研系列-操作系统:第二章、进程与线程
  • Screen 连接远程服务器(Ubuntu)
  • 视觉中国:镜头下的中国发展图景
  • 网站建设开发定制/深圳广告公司排名
  • 常德建设企业网站/抖音的商业营销手段
  • 政府网站的模块结构/网络广告类型
  • 铜陵网站制作公司/怎么申请建立网站
  • 个人网站备案名称/seo关键词排名优化品牌
  • 手机网站开发标准/济源新站seo关键词排名推广