首页 > 编程语言 >【C#进阶】高级面向对象特性_2024-06-22

【C#进阶】高级面向对象特性_2024-06-22

时间:2024-06-22 11:45:10浏览次数:3  
标签:06 进阶 22 void 特性 WriteLine Console 方法 public

一、概念

1. 高级面向对象特性

面向对象编程(OOP)是一种编程范式,它使用“对象”来设计软件。这些对象可以包含数据和行为。高级面向对象特性包括:

  • 封装:把数据和操作这些数据的代码打包在一起,不让外部直接访问数据,而是通过方法来操作。
  • 继承:允许新创建的类(子类)继承现有类(父类)的属性和方法,但可以添加或重写自己的特性。
  • 多态:让不同的对象可以对同一消息做出响应,但具体的行为会根据对象的实际类型而有所不同。

2. 接口和抽象类

  • 接口(Interface):可以想象成一个“合同”,它规定了类必须实现的方法和属性,但不提供实现细节。任何类都可以实现多个接口。
  • 抽象类(Abstract Class):是一个不能被实例化的类,通常包含一些抽象方法(没有实现的方法),子类必须提供这些方法的具体实现。

3. 委托和事件

  • 委托(Delegate):可以看作是一个类型安全的函数指针,可以指向任何符合其签名的方法。
  • 事件(Event):是一种特殊的多播委托,用于对象之间的通信。一个对象可以“发布”事件,其他对象可以“订阅”这些事件。

4. 异常高级处理

  • 异常是程序运行时出现的错误。C#提供了一套机制来捕获和处理这些错误。
  • 你可以使用try块来包围可能出错的代码,catch块来捕获并处理特定的异常,finally块来执行无论是否发生异常都需要执行的代码。

5. 反射和特性

  • 反射(Reflection):允许程序在运行时查询和操作对象的类型信息,比如获取类的属性、方法等。
  • 特性(Attribute):是一种标记,可以附加到代码元素上(比如类、方法),用来提供元数据信息。这些信息可以在运行时通过反射读取。

二、实例展示

1. 接口和抽象类

接口(Interface):想象一下,你经营一家餐厅,规定所有员工都必须会“服务顾客”。不论他们是厨师、服务员还是收银员,这个“服务顾客”的能力就像是一个约定。在C#里,我们用接口来定义这样的约定。接口只说你“必须”做什么,但具体怎么做,它不管。

// 定义一个接口 ICustomerService
public interface ICustomerService
{
    // 规定所有实现这个接口的类,都必须有 ServeCustomer 这个方法
    void ServeCustomer();
}

// 厨师类实现接口
public class Chef : ICustomerService
{
    public void ServeCustomer()
    {
        Console.WriteLine("厨师微笑着给顾客上菜。");
    }
}

抽象类(Abstract Class):如果说接口是严格的“你必须做”,那么抽象类就是“我给你一些基础,你再根据需要扩展”。抽象类可以有具体实现的方法,也可以有抽象方法(就是只有方法名,没有具体实现)。

public abstract class Employee
{
    // 具体实现的方法
    public void Greet()
    {
        Console.WriteLine("欢迎光临!");
    }

    // 抽象方法,留给子类去实现
    public abstract void DoWork();
}

public class Waiter : Employee
{
    public override void DoWork()
    {
        Console.WriteLine("服务员忙着点单。");
    }
}

2. 委托和事件

委托(Delegate):想象你在餐厅里放了一个意见箱,任何人都可以往里面投递反馈,而你定期检查并处理这些反馈。委托就像这个意见箱,它允许你定义一个方法的类型,然后你可以将多个方法像纸条一样丢进去,最后一起或单独调用它们。

public delegate void FeedbackHandler(string feedback);

public class Restaurant
{
    public event FeedbackHandler NewFeedback;

    public void ReceiveFeedback(string feedback)
    {
        Console.WriteLine($"收到反馈: {feedback}");
        
        // 如果有注册的方法,就调用它们
        NewFeedback?.Invoke(feedback);
    }
}

// 使用委托
Restaurant myRestaurant = new Restaurant();
myRestaurant.NewFeedback += DisplayFeedbackOnScreen;
myRestaurant.NewFeedback += LogFeedbackToFile;

// 显示反馈到屏幕上
private static void DisplayFeedbackOnScreen(string feedback)
{
    Console.WriteLine($"屏幕上显示: {feedback}");
}

// 将反馈记录到文件
private static void LogFeedbackToFile(string feedback)
{
    // 实现日志记录逻辑
    Console.WriteLine($"记录到文件: {feedback}");
}

3. 异常高级处理

异常处理就像餐厅里应对突发事件的预案。如果厨房突然没煤气了(异常),你不希望整个餐厅停止服务,而是要优雅地告诉顾客“稍等,我们正在解决”,同时后台紧急处理问题。

try
{
    // 尝试执行可能会出错的代码,比如打开一个不存在的文件
    using (StreamReader file = new StreamReader("不存在的文件.txt"))
    {
        string content = file.ReadToEnd();
    }
}
catch (FileNotFoundException)
{
    // 如果找不到文件,友好提示用户
    Console.WriteLine("抱歉,文件找不到了。");
}
finally
{
    // 不管是否出错,这里都会执行,用于清理资源
    Console.WriteLine("操作完成,清理中...");
}

4. 反射和特性

反射(Reflection):就像拥有一面神奇的镜子,能让你在程序运行时查看和操作类、属性、方法等信息。比如,你的餐厅需要根据菜单动态调整价格,反射就能帮助你获取菜单上所有菜品的信息,并修改它们的价格。

using System.Reflection;

public class Dish
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public class Program
{
    public static void AdjustPrices(object obj)
    {
        Type type = obj.GetType();
        
        PropertyInfo[] properties = type.GetProperties();
        foreach (PropertyInfo prop in properties)
        {
            if (prop.Name == "Price")
            {
                prop.SetValue(obj, (decimal)prop.GetValue(obj) * 1.1m); // 调整价格
            }
        }
    }

    public static void Main(string[] args)
    {
        Dish spicyChicken = new Dish { Name = "辣子鸡", Price = 50.0m };
        AdjustPrices(spicyChicken);
        Console.WriteLine($"调整后辣子鸡的价格: {spicyChicken.Price}");
    }
}

特性(Attribute):特性就像给餐厅的菜品贴上标签,比如“新品”、“热销”等。在代码里,特性是一种元数据,用来给类、方法等添加额外的信息。

[MenuCategory("热销")]
public class SpicyChicken : Dish
{
    // 省略具体实现...
}

// 获取特性
var type = typeof(SpicyChicken);
var categoryAttr = (MenuCategoryAttribute)Attribute.GetCustomAttribute(type, typeof(MenuCategoryAttribute));
Console.WriteLine($"菜品分类: {categoryAttr.Category}");

如果你直接输入上面这段代码你会发现报错缺少引用,之所以报错,是因为MenuCategory这个特性类没有被定义。特性(Attribute)在C#中是一个特殊的类,通常继承自System.Attribute基类。在使用自定义特性前,你需要先定义它。下面来补充完整这部分内容:

首先,定义一个名为MenuCategoryAttribute的特性类。这个类需要继承自System.Attribute,并且你可以为其定义属性,比如这里的Category

using System;

// 定义MenuCategory特性类
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] // 控制特性使用的范围和是否可重复
public class MenuCategoryAttribute : Attribute
{
    public string Category { get; }

    public MenuCategoryAttribute(string category)
    {
        Category = category;
    }
}

接下来,你之前的代码就可以正常工作了,因为现在MenuCategory特性已经被正确定义了。

[MenuCategory("热销")] // 现在这部分应该不会报错了
public class SpicyChicken : Dish
{
    // 省略具体实现...
}

// 获取特性
var type = typeof(SpicyChicken);
var categoryAttr = (MenuCategoryAttribute)Attribute.GetCustomAttribute(type, typeof(MenuCategoryAttribute));

if (categoryAttr != null)
{
    Console.WriteLine($"菜品分类: {categoryAttr.Category}");
}
else
{
    Console.WriteLine("未找到MenuCategory特性");
}

记得包含对自定义特性类所在命名空间的引用,如果特性类不在同一命名空间下的话。这样,你就能成功地定义和使用自定义特性了。

三、总结

  1. 接口(Interface)

    • 定义了一组方法签名,任何实现该接口的类都需要提供这些方法的具体实现。
    • 用于确保不同类间的一致性或共享特定功能集的约定。
    • 接口中所有成员默认为公有,且只能定义方法、属性、索引器和事件。
  2. 抽象类(Abstract Class)

    • 可以包含抽象方法(无具体实现)和具体实现的方法。
    • 不能直接实例化,用于作为其他类的基类,强制子类实现特定方法。
    • 提供了一定程度的代码复用和结构规划。
  3. 委托(Delegate)

    • 类似于函数指针,用于封装方法的引用,支持多播(绑定多个方法)。
    • 在事件处理、回调函数等场景中广泛使用。
    • C#中的Lambda表达式和Action、Func泛型委托进一步简化了委托的使用。
  4. 事件(Event)

    • 基于委托的一种通信机制,用于在类内部状态改变时通知外部代码。
    • 通常包含一个add和remove访问器,用于管理委托链表。
    • 事件发布者触发事件,事件订阅者通过提供事件处理方法响应。
  5. 异常处理

    • 用于处理程序运行时可能出现的错误情况,保证程序健壮性。
    • 包括try-catch-finally结构,用于捕获并处理异常,以及finally块确保清理资源。
    • 可以自定义异常类,更精确地描述错误类型。
  6. 反射(Reflection)

    • 在运行时动态获取类型信息(如类名、属性、方法等)并操作这些信息的技术。
    • 用于实现诸如插件系统、序列化、动态类型创建等高级功能。
    • 性能开销相对较高,应谨慎使用。
  7. 特性(Attribute)

    • 为程序元素(如类、方法、属性)提供元数据的途径。
    • 特性以[@AttributeName]形式应用,可通过反射读取。
    • 用于标记、配置或给编译器和运行时提供指令,增强代码的描述性和可操作性。

每个知识点都是C#面向对象编程中不可或缺的一部分,掌握它们能让你编写出更灵活、高效、易于维护的代码。

标签:06,进阶,22,void,特性,WriteLine,Console,方法,public
From: https://www.cnblogs.com/Jason54/p/18262046

相关文章

  • 【C#进阶】高级数据结构和算法_2024-06-22
    当我们深入到编程的世界,我们会发现,掌握高级数据结构和算法就像是拥有了一套高级工具箱,它们能帮助我们更高效、更优雅地解决问题。今天,我们就来一探究竟,看看这些高级工具是如何工作的。首先,让我们来谈谈高级数据结构。数据结构就像是我们用来存放东西的容器,高级数据结构就是一些......
  • Midas Civil2022安装使用教程
    MidasCivil是一款先进的桥梁与土木工程结构分析设计软件,专为桥梁工程师打造。它集成了强大有限元分析引擎,支持从初步设计到详细设计全过程,提供桥梁结构静力分析、动力分析、稳定性评估、抗震设计等功能。用户通过直观界面,能够高效建模、仿真各类复杂工况,确保结构安全性与经济......
  • [题解]AT_abc225_f [ABC225F] String Cards
    思路Part1弱化版看到这道题的第一眼想到了P1012这道题。但是,这两道题选择的数量是有区别的。我们可以由拼数得出一个结论性的排序规则(这里就不多做解释了):inlineboolcmp(stringa,stringb){returna+b<b+a;}如果用这样的做法,有hack。Part2状态......
  • [题解]AT_abc225_e [ABC225E] フ
    思路对于每一个7,我们都可以抽象为这样一个图形:如果有两个7,无论它是否有重合部分,红色部分是不需要判断的,只需要看绿色的部分。因此,我们的问题就简化为了三角形,而不是四边形。对于所有的7,都有一个公共顶点:\((0,0)\)点。所以,我们可以引出一个叫斜率的概念来判断这些三角形......
  • [题解]AT_abc225_d [ABC225D] Play Train
    题意给定\(N\)个小车,每个小车的编号分别为:\(1,2,\dots,N\)。现在有\(Q\)个操作,每个操作执行\(3\)种操作:1xy,将\(x\)和\(y\)相连。(\(y\)在\(x\)之后)2xy,将\(x\)和\(y\)的连接解除。3x,输出\(x\)所在链的长度,及其这条链中的所有元素。(从前往后)思路我......
  • [题解]AT_abc224_e [ABC224E] Integers on Grid
    比较符合CCF造数据水平的题。思路首先可以用两个vector<pair<int,int>>v[N]分别将每一行、每一列的元素的权值与编号存储下来。那么可以对所有的\(v_i\)按照权值从小到大排序。那么发现对于所有的满足v[i][p].fst<v[i][q].fst的\((p,q)\)都可以建一条从\(p\)指......
  • [题解]AT_abc222_f [ABC222F] Expensive Expense
    板子题,模拟赛场切了。思路线段树换根板子题。因为需要求每一个点的答案,所以定义\(dp_i\)表示以\(i\)为根的最长距离。考虑将一个点\(v\)转化为根,树的形态会发生什么变化(假设\(v\)的父亲节点是\(u\))。发现在\(v\)子树中的节点,距离都会减少\(w_{u\tov}\),其它节点......
  • 063java jsp ssm企业员工培训管理系统员工培训计划培训记录管理(源码+数据库+文档)
    项目技术:Spring+SpringMVC+MyBatis等等组成,B/S模式管理等等。环境需要1.运行环境:最好是javajdk1.8,我们在这个平台上运行的。其他版本理论上也可以。2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA;3.tomcat环境:Tomcat7.x,8.x,9.x版本均可4.硬件环境:windows7/8/10......
  • 061java jsp ssm共享充电宝管理系统(源码+数据库+文档)
     项目技术:Spring+SpringMVC+MyBatis等等组成,B/S模式管理等等。环境需要1.运行环境:最好是javajdk1.8,我们在这个平台上运行的。其他版本理论上也可以。2.IDE环境:IDEA,Eclipse,Myeclipse都可以。推荐IDEA;3.tomcat环境:Tomcat7.x,8.x,9.x版本均可4.硬件环境:windows7/8/1......
  • 代码随想录算法训练营第十四天 | 226.翻转二叉树 101.对称二叉树 104.二叉树的最大深
    226.翻转二叉树题目:给你一棵二叉树的根节点root,翻转这棵二叉树,并返回其根节点。解题:思路:遍历的过程中交换每个节点的左右孩子。选择哪种遍历方式?中序不行,左中右,左边子节点交换完,处理中间交换了左节点和右节点,再处理右节点去交换时这个右节点就是原来的左节点,所以有一边就一......