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

C#基础08-面向对象

零、文章目录

C#基础08-面向对象

1、面向对象三大特性

(1)封装(Encapsulation)
  • 核心思想:隐藏对象内部细节,仅暴露必要接口,通过访问修饰符控制数据安全。
  • 访问修饰符
    • private:仅本类内可访问(默认修饰符)
    • protected:本类及子类可访问
    • internal:同一程序集内可访问
    • public:全局可访问
    • protected internalprotected + internal 权限之和
  • 实现方式
    • 字段封装:私有字段 + 公共属性(如 private string _name; public string Name { get; set; }
    • 方法封装:仅公开必要方法,隐藏内部逻辑(如数据验证)
public class BankAccount {private double _balance;  // 私有字段 public void Deposit(double amount) {  // 公开方法 if (amount > 0) _balance += amount;}
}
  • 设计原则
    • 单一职责原则(SRP):一个类只负责一项功能
    • 开闭原则(OCP):对扩展开放,对修改关闭
(2)继承(Inheritance)
  • 核心思想:子类复用父类特性,并扩展新功能。
  • 关键规则
    • 单继承:C# 仅支持单继承(如 class Dog : Animal
    • 里氏替换原则:子类对象可替代父类对象(如 Animal animal = new Dog();
    • 构造方法顺序:先执行父类构造方法,再执行子类
    • 成员继承:子类继承父类所有成员(包括私有成员,但不可直接访问)
  • 实现方式
    • 类继承:子类继承父类属性和方法
    • 抽象类与接口
      • 抽象类(abstract):包含未实现方法,需子类重写
      • 接口(interface):纯契约定义,无实现
public class Animal {public virtual void Speak() => Console.WriteLine("Animal sound");
}
public class Dog : Animal {public override void Speak() => Console.WriteLine("Bark!");  // 重写父类方法
}
  • 禁用继承:用 sealed 修饰类(如 sealed class FinalClass
(3)多态(Polymorphism)
  • 核心思想:同一操作作用于不同对象时,表现出不同行为。
  • 编译时多态(静态)
    • 方法重载:同名方法不同参数(参数类型/数量不同)
public class Calculator {public int Add(int a, int b) => a + b;public double Add(double a, double b) => a + b;  // 重载
}
- 方法隐藏:子类用 `new` 隐藏父类方法(非重写)  
public class Parent { public void Print() => Console.WriteLine("Parent"); }
public class Child : Parent { public new void Print() => Console.WriteLine("Child");  // 隐藏父类方法
}
  • 运行时多态(动态)
    • 虚方法重写(virtual + override):
Animal animal = new Dog();
animal.Speak();  // 输出 "Bark!"(运行时根据实际对象类型决定)
- 抽象方法重写(`abstract`):父类声明抽象方法,子类强制实现  
- 接口多态:通过接口引用调用不同实现  
interface IDrawable { void Draw(); }
class Circle : IDrawable { public void Draw() => Console.WriteLine("Drawing circle"); }
class Square : IDrawable { public void Draw() => Console.WriteLine("Drawing square"); }IDrawable shape = new Circle();
shape.Draw();  // 输出 "Drawing circle"
  • 多态优势
    • 提高代码扩展性:新增子类无需修改父类逻辑
    • 增强灵活性:同一接口处理不同对象(如 List<Animal> 存储多种动物)
(4)三大特性对比表
特性核心目的关键实现设计原则
封装数据安全与简化使用访问修饰符 + 属性/方法封装单一职责原则 (SRP)
继承代码复用与层次化设计类继承 (:) + 抽象类/接口里氏替换原则 (LSP)
多态接口统一与行为多样化重载/重写 (override)/接口实现依赖倒置原则 (DIP)
(5)实战建议
  • 封装场景:敏感数据(如密码)设为 private,通过公共方法访问。
  • 继承陷阱:避免过度继承导致“脆弱基类问题”,优先使用组合。
  • 多态优化:
    • virtual/override 替代 new 实现真正多态
    • 接口多态适用于跨组件协作(如插件系统)
  • SOLID 补充:结合开闭原则(OCP)和接口隔离原则(ISP)提升设计质量。

2、访问修饰符

(1)访问范围从宽到严
  • public
    • 权限:无限制访问
    • 适用对象:类、成员(字段/方法/属性)
    • 场景:跨程序集公开API
public class Logger { public string LogPath; } // 任意程序集可访问
  • protected internal
    • 权限:protected + internal 的并集(当前程序集 或 任意派生类)
    • 场景:组件库中供派生类扩展的接口
protected internal void Initialize() { } // 当前程序集或子类可用 
  • internal
    • 权限:仅当前程序集内可访问(默认类访问级别)
    • 场景:模块内部实现隐藏
internal class Cache { } // 仅本项目可见 
  • protected
    • 权限:当前类 及派生类(不限程序集)
    • 场景:设计可继承框架
protected virtual void OnStart() { } // 子类可重写 
  • private
    • 权限:仅当前类内部(成员默认访问级别)
    • 场景:封装内部状态
private string _connectionKey; // 仅本类访问 
(2)关键规则与限制
规则类型说明示例
类修饰符限制类仅支持 publicinternal(默认internalinternal class Utility → 禁止跨程序集实例化
成员可访问性成员不能比其所属类更开放(如 internal 类中不能声明 public 成员)internal class A { public void Foo() } → 编译错误
接口/显式实现接口成员或显式接口实现禁止使用访问修饰符interface IDevice { void Run(); } → 隐含 public
跨程序集继承派生类访问基类protected成员时,需遵守基类程序集的internal限制基类internal成员 → 即使protected,外部程序集派生类仍不可访问
(3)权限范围对比表
修饰符当前类同程序集派生类同程序集非派生类跨程序集派生类跨程序集非派生类
public✔️✔️✔️✔️✔️
protected internal✔️✔️✔️✔️
internal✔️✔️✔️
protected✔️✔️✔️
private✔️
  • 设计原则:
    • 优先用 private 封装细节,通过公共方法暴露功能
    • 库开发时,用 internal 隐藏非公开API,protected 预留扩展点
    • 避免滥用 public(增大耦合风险)和 protected internal(增加理解成本)
(4)常见误区与陷阱
  • 默认权限混淆
    • 类默认 internal,成员默认 private → 未显式声明时易导致访问错误
  • 跨程序集保护失效
// 程序集A
public class Base { protected int Key; } 
// 程序集B(引用A)
class Derived : Base { void UseKey() { Console.Write(Key); } // ✅ 可访问 static void LeakKey(Base b) { Console.Write(b.Key); // ❌ 编译错误:跨程序集仅能通过派生类实例访问}
}
  • private protected(C# 7.2+)
    • 限制比 protected internal 更严:仅允许 同一程序集中的派生类
private protected string _secret; // 当前类或同程序集派生类可访问
(5)总结与最佳实践
  • 安全优先:成员起始设为 private,按需放宽权限
  • 组件设计:
    • public → 稳定接口
    • internal → 内部实现
    • protected → 扩展点
  • 代码审查:检查所有 public 成员是否必要,减少全局暴露

3、继承

(1)基础概念
  • 定义与作用
    • 继承:子类(派生类)基于父类(基类)创建,自动获得父类非私有成员(字段/方法/属性)
    • 目的:实现代码复用、逻辑分层(如将通用字段 ID/CreateTime 提取至基类)
    • 特性:
      • C# 仅支持单继承(一个子类只能有一个直接父类)
      • 未指定父类时,默认继承 System.Object
  • 语法结构
class 父类 { /* 成员定义 */ }  
class 子类 : 父类 { /* 新增或重写成员 */ }  // 继承声明 
(2)关键特性与规则
  • 构造函数执行顺序:
    • 子类实例化时按以下顺序执行构造函数
    • 若无显式构造函数,系统自动生成无参构造方法

  • 成员访问控制
关键字子类访问权限示例
public✅ 可直接访问子类.字段名
protected✅ 可直接访问子类.字段名
private❌ 不可访问需通过父类公共方法间接访问
internal同程序集内可访问跨类但同项目
  • 方法重写与隐藏:重写影响多态行为;隐藏仅覆盖当前子类。
方式关键字特点示例
重写override修改父类虚方法逻辑(需父类方法标记 virtualpublic override void Method()
隐藏new创建与父类同名的新方法,隐藏继承的原始方法public new void Method()
(3)进阶特性与注意事项
  • 多层继承传递性:若 C → B → A,则 C 继承 BA 的所有非私有成员
class Animal {}  
class Mammal : Animal {}  // 继承Animal  
class Dog : Mammal {}     // 继承Mammal(间接继承Animal)  
  • 避免多重继承歧义:C# 不支持多父类继承(如 class C : A, B 会报错),需通过接口实现多重能力。
  • 装箱与拆箱影响:继承链中值类型与引用类型转换可能引发性能损耗(如 object obj = new Dog();)。
(4)实战示例
  • 场景:手机类继承体系
// 父类:基础手机属性 
class Phone {public string Color { get; set; }public double Price { get; set; }public Phone(string color, double price) {Color = color; Price = price;}
}// 子类:扩展电池属性 
class CellPhone : Phone {public string MaxBatteryLife { get; set; }// 调用父类构造 + 子类扩展 public CellPhone(string color, double price, string battery) : base(color, price)  // 调用父类构造函数 {MaxBatteryLife = battery;}
}// 使用
var myPhone = new CellPhone("Black", 3999.99, "48小时");
Console.WriteLine($"颜色:{myPhone.Color}, 续航:{myPhone.MaxBatteryLife}");
  • 关键点:
    • 子类通过 : base(...) 传递参数至父类构造器
    • 子类直接使用父类属性 Color/Price
(5)常见错误及规避
  • 未调用父类构造导致初始化失败
class Child : Parent {public Child() { }  // 错误!未显式调用父类构造// 修正:public Child() : base() { }
}
  • 混淆重写与隐藏:多态场景下,new 隐藏方法不会覆盖父类引用调用结果
Parent obj = new Child();
obj.Method();  // 若Child.Method用new隐藏,此处仍调用Parent.Method 
(6)总结建议
  • 优先组合而非继承:过度继承易导致层级复杂,推荐用组合(类成员引用其他类)替代。
  • 合理使用 sealed:对无需再派生的类标记 sealed 阻止继承,提升安全性。
  • 实战练习:对比 struct(值类型无继承)与 class 的适用场景。

4、接口

(1)本质与核心特性
  • 契约式设计
    • 接口定义类或结构体必须实现的方法、属性、事件或索引器签名,但不含具体实现。
    • 示例:
public interface ILogger {void Log(string message);  // 方法签名string LogLevel { get; set; }  // 属性签名 
}
  • 关键特性
    • 多重继承:一个类可实现多个接口,突破 C# 单继承限制。
    • 解耦与标准化:强迫实现类遵循统一规范,提升代码可维护性。
    • 默认公开性:接口成员隐式为 public,不可添加访问修饰符。
(2)核心应用场景
  • 实现多态与灵活替换
IAnimal animal = new Dog();  // 多态引用
animal.Speak();              // 输出 "Woof!"
animal = new Cat();          // 动态替换实现类
animal.Speak();              // 输出 "Meow"
  • 支持设计模式
    • 策略模式:通过接口封装算法族,运行时切换策略
public interface ISortStrategy { void Sort(List<int> data); }
public class QuickSort : ISortStrategy { /* 实现 */ }
public class Context { private ISortStrategy _strategy;public void SetStrategy(ISortStrategy strategy) => _strategy = strategy;
} 
- 工厂模式:接口定义创建契约,子类决定实例化逻辑。
  • 组件化开发:定义数据访问层接口 IDataAccess,支持切换不同数据库实现:
public class MongoDBService : IDataAccess { /* MongoDB 实现 */ }
public class SqlService : IDataAccess { /* SQL Server 实现 */ } 
  • 跨模块通信:事件驱动架构中,通过接口标准化事件处理:
public interface IEventHandler {void Handle(Event e);
}
(3)高级特性与注意事项
  • 显式接口实现:解决同名方法冲突,通过接口名限定调用:
void IInterfaceA.Method() { }  // 显式实现
  • 接口继承链:接口可多重继承其他接口,合并契约:
public interface IComboBox : ITextBox, IListBox { } 
  • 泛型接口:增强类型安全性与复用性:
public interface IRepository<T> {T GetById(int id);
} 
  • 使用限制
    • 不可包含字段/构造函数:仅定义行为契约。
    • 默认方法(C# 8.0+):允许接口提供默认实现,减少破坏性升级。
(4)最佳实践总结
  • 命名规范:接口名以 I 开头(如 IEnumerable)。
  • 单一职责:每个接口聚焦单一功能(如 ISaveable 而非 IFileOperations)。
  • 接口隔离:避免“胖接口”,按需拆分为小接口。
  • 依赖倒置:高层模块依赖抽象接口,而非具体实现。

5、抽象类

(1)基础概念
  • 定义与特性
    • 使用 abstract 关键字声明抽象类,如:
public abstract class Animal  // 抽象类 
{public abstract void MakeSound();  // 抽象方法(无实现)public void Sleep()                // 非抽象方法(有默认实现){Console.WriteLine("Sleeping...");}
}
- 核心特性:  * ❗ 不可实例化:不能通过 `new` 创建对象(如 `new Animal()` 非法)。  * ✅ 可包含混合成员:可同时有抽象方法(无方法体)和非抽象方法(有实现)。  * 🔒 强制子类实现:非抽象子类必须重写所有抽象方法(否则编译错误)。
  • 设计目的
    • 为相关类提供共性模板(如动物都有 MakeSound 行为),具体实现由子类完成。
    • 解决类族中 “部分行为需自定义,部分行为可复用” 的问题。
️(2)核心规则
  • 抽象方法约束
    • 抽象方法只能存在于抽象类中,且无方法体(以分号结尾):
public abstract void Eat();  // 仅声明,无实现 
- 子类必须通过 `override` 实现:
public class Dog : Animal 
{public override void MakeSound() => Console.WriteLine("Woof!");
}
  • 非抽象成员支持
    • 抽象类可包含字段、属性、构造函数和具体方法:
public abstract class Fruit 
{public string Color { get; set; }  // 具体属性public abstract float Price { get; } // 抽象属性
}
  • 构造与继承机制
    • 抽象类可以有构造函数(通常用于初始化公共字段)。
    • 支持多层继承(如 Animal → Mammal → Dog)。
(3)抽象类 vs 接口
特性抽象类 (abstract class)接口 (interface)
实现继承✅ 单继承✅ 多实现
方法实现✅ 可含具体方法❌ 仅方法签名
字段/属性✅ 可包含字段和属性初始值❌ 仅自动属性(无字段)
设计目标表征 IS-A 关系(如狗是动物)表征 CAN-DO 能力(如可飞行)
  • 决策建议:
    • 需多态且无关类共享行为 → 接口(如日志服务 ILogger)。
    • 存在通用代码需复用 → 抽象类(如游戏实体 GameEntity 基类)。
(4)典型应用场景
  • 框架设计(如游戏角色系统):
public abstract class Character {public int Health { get; set; }public abstract void Attack();  // 攻击方式由子类定义 public void TakeDamage(int damage) => Health -= damage; // 通用逻辑
}
public class Warrior : Character {public override void Attack() => Console.WriteLine("Sword slash!");
}
  • 强制规范工具类
public abstract class Logger {public abstract void Log(string message);  // 子类必须实现日志写入方式public void LogError(string error) => Log($"[ERROR] {error}"); // 通用封装 
}
️(5)关键注意事项
  • 禁止密封:抽象类不可用 sealed 修饰(否则无法继承)。
  • 构造函数用途:仅用于子类初始化(如 public Dog() : base("Mammal"))。
  • 多态性支持:可通过基类引用调用子类实现(如 Animal a = new Dog(); a.MakeSound();)。

6、方法重写

(1)基础概念
  • 定义与目的
    • 重写(Override):派生类修改基类中声明为virtualabstract的方法实现,实现多态性。
    • 核心价值:
      • 扩展基类功能,支持差异化行为(如不同动物的叫声)。
      • 符合开闭原则(对扩展开放,对修改关闭)。
  • 语法规则
角色关键字示例
基类方法virtualpublic virtual void Speak() { ... }
派生类方法overridepublic override void Speak() { ... }
  • 关键限制:
    • 静态方法、私有方法(private)不可重写;
    • 重写方法必须与基类方法完全一致(名称、参数、返回值)。
(2)核心机制
  • 多态性实现:通过基类引用调用方法,运行时自动绑定派生类实现(动态绑定)。
Animal dog = new Dog();  
dog.Speak(); // 输出"狗叫:汪汪!"(实际类型决定行为)  
  • 调用基类实现:使用base关键字访问被重写的基类方法:
public class Car : Vehicle {  public override void Start() {  base.Start(); // 先执行基类启动逻辑  Console.WriteLine("引擎点火"); // 扩展行为  }  
} 
  • 抽象方法重写:抽象类中声明abstract方法,强制派生类重写:
public abstract class Shape {  public abstract void Draw(); // 无实现  
}  
public class Circle : Shape {  public override void Draw() => Console.WriteLine("绘制圆形"); // 必须实现  
} 
(3)重写 vs 隐藏
特性重写(override)隐藏(new)
基类要求virtual/abstract方法任意方法(无需virtual
多态行为运行时按实际类型调用派生类方法编译时按声明类型调用
调用结果Animal obj = new Dog(); obj.Speak() → 调用Dog.Speak()Animal obj = new Dog(); obj.Speak() → 调用Animal.Speak()
  • 优先使用重写:确保多态性,避免隐藏导致的逻辑混淆。
️(4)实战应用场景
  • 定制化行为(如不同动物叫声)
public class Cat : Animal {  public override void Speak() => Console.WriteLine("猫叫:喵喵!");  
}  
  • 扩展基类功能(如车辆启动流程增强)
public class ElectricCar : Car {  public override void Start() {  base.Start(); // 保留基类启动逻辑  Console.WriteLine("电池系统激活"); // 新增步骤  }  
} 
  • 实现设计模式(如模板方法模式)
public abstract class GameAI {  public void Turn() {  CollectResources();  BuildStructures(); // 可重写的步骤  }  protected virtual void BuildStructures() { } // 默认空实现  
}  
public class OrcAI : GameAI {  protected override void BuildStructures() => Console.WriteLine("建造兽人兵营");  
} 
(5)关键注意事项
  • 访问权限:重写方法访问级别需与基类一致(如public重写public)。
  • 异常处理:重写方法抛出的异常类型必须与基类相同或是其子类。
  • 性能优化:避免深度继承链中频繁重写,可能导致调用栈过深。
  • 调试技巧:使用base调试基类逻辑,用this验证派生类行为,结合断点观察多态调用链。

7、命名空间

(1)核心作用
  • 解决命名冲突
    • 将全局作用域划分为独立区块,避免不同库中同名类型/函数冲突。
    • 使用时通过完整限定名区分:CompanyA.Project.Logger vs CompanyB.Project.Logger
namespace CompanyA.Project { class Logger { } }
namespace CompanyB.Project { class Logger { } }
  • 代码组织与封装
    • 类似文件系统的文件夹结构,将相关类型分组管理(如System.IO处理输入输出)。
    • 支持嵌套命名空间(如System.Collections.Generic),实现逻辑分层。
(2)语法与使用方式
  • 定义命名空间
namespace MyApplication.Data {class Database { }  // 实际类型名为 MyApplication.Data.Database
}
  • 引用命名空间
    • 完全限定名:直接使用完整路径(System.Console.WriteLine())。
    • using指令:简化代码,避免重复书写命名空间:
using System;
Console.WriteLine("Hello");  // 无需写 System.Console 
- 别名(Alias):解决同名冲突或简化长命名空间:  
using ProjectA = CompanyA.Project;
ProjectA.Logger.Log();  // 调用 CompanyA.Project.Logger 
(3)实际应用场景
  • 类库开发
    • 第三方库(如NuGet包)必须使用独立命名空间,防止污染用户全局作用域。
    • 示例:ST硬件驱动库通过命名空间封装外设寄存器组,提高可读性。
  • 大型项目分层
    • 推荐结构:
namespace App.BusinessLogic;  // 业务逻辑层
namespace App.DataAccess;     // 数据访问层 
namespace App.WebUI;          // 表示层
- 分层后,各模块通过`using`按需引用,减少耦合。
  • 与物理文件的关系
    • 命名空间可跨多个文件定义(非连续),例如:
      • File1.cs: namespace MyLib { class A { } }
      • File2.cs: namespace MyLib { class B { } }
        编译器自动合并为同一命名空间。
(4)最佳实践与注意事项
  • 避免全局污染
    • 慎用using namespace *;(如using namespace System),尤其在头文件中,易引发冲突。
    • 优先使用局部using或完全限定名。
  • 命名规范
    • 采用公司/项目名作为根命名空间(如Microsoft.Azure)。
    • 层次清晰:<Company>.<Product>.<Module>
  • 未命名命名空间:用于文件内私有类型(等效于internal访问修饰符),限制外部访问:
namespace { class InternalHelper { }  // 仅在当前程序集可见 
}
http://www.dtcms.com/a/431446.html

相关文章:

  • 网站建设公司费用网站开发遵循
  • php做网站 价格商城网站开发技术可行性分析
  • 10.仅使用 CSS 实现波浪形卡片 UI 设计
  • 太原市手机微网站建设网络推广都有哪些方式
  • display ospf interface 概念及题目
  • 专栏导航:《数据中心网络与异构计算:从瓶颈突破到架构革命》
  • 基层单位不能建设网站织梦做有网站有后台 能下载备份所有代码文件么
  • 爱网站关键词查询工具长尾美食网站建设项目预算
  • Swift 属性
  • 服务器做网站用什么环境好页游平台网站
  • 在手机上做网站是什么软件网店推广软件
  • 无锡网站建设服务公司如何给网站的关键词做排名
  • java线上问题排查-占用内存的大对象
  • 公司网站维护一年多少钱做网站网站代理
  • 【51单片机计时器1中断的60秒数码管倒计时】2023-1-23
  • 广州网站建设知名乐云seo淘宝上开做网站的店铺
  • 品牌型网站成功案例图片五是做好纪检监察网站建设
  • 【文献笔记】remote sensing 2024 | PointStack
  • Vue2 学习记录
  • 手写MyBatis第87弹:从SqlNode树到可执行SQL的转换奥秘
  • Hot100——普通数组
  • Linux 软件安装和进程管理
  • [创业之路-645]:手机属于通信?还是属于消费类电子?还是移动互联网?
  • 网站建设 交易保障公众号推广一个6元
  • Nodejs--如何获取前端请求
  • 【项目】基于Spring全家桶的论坛系统 【下】
  • 红黑树可视化工具
  • 深圳公司网站建设设徐州关键词优化排名
  • 三角函数速度规划方法介绍
  • 安卓基础组件020-页面跳转传递复杂数据002