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

C# 类和继承(扩展方法)

扩展方法

在迄今为止的内容中,你看到的每个方法都和声明它的类关联。扩展方法特性扩展了这个边
界,允许编写的方法和声明它的类之外的类关联。
想知道如何使用这个特性,请看下面的代码。它包含类MyData,该类存储3个double类型
的值,并含有一个构造函数和一个名为Sum的方法,该方法返回3个存储值的和。
在现实世界的开发中,扩展方法是一个特别有用的工具。事实上,几乎整个LINQ库都是通
过扩展方法来实现的。

class MyData
{private double D1;   //字段private double D2;private double D3;public MyData(double d1,double d2,double d3)   //构造韩{D1=d1;D2=d2;D3=d3;}public double Sum()      //方法{return D1+D2+D3;}
}

这是一个非常有限的类,但假设它还含有另外一个方法会更有用,该方法返回3个数据的平
均值。使用已经了解的关于类的内容,有几种方法可以实现这个额外的功能。

  • 如果你有源代码并可以修改这个类,你只需要为这个类增加这个新方法。
  • 然而,如果不能修改这个类(如这个类在一个第三方类库中),那么只要它不是密封的,
    你就能把它用作一个基类并在派生自它的类中实现这个额外的方法。

然而,如果不能访问代码,或该类是密封的,或有其他的设计原因使这些方法不适用,就不
得不在另一个使用该类的公有可用成员的类中编写一个方法。
例如,可以编写一个下面这样的类。下面的代码包含一个名为ExtendMyData的静态类,它
含有一个名为Average的静态方法,该方法实现了额外的功能。注意该方法接受MyData的实例作为参数。

static class ExtendMyData 
{public static double Average(MyDat md)  //MyData类的实例{return md.Sum()/3;  .使用MyData的实例}
}class Program
{static void Main(){MyData md=new MyData(3,4,5);Console.WriteLine("Average:{0}",ExtendMyData.Average(md));//MyData的实例 调用静态方法}
}

运行结果

avergage=4

尽管这是非常好的解决方案,但如果能在类的实例自身上调用该方法,而不是创建另一个作用
于它的类的实例,将会更优雅。下面两行代码阐明了它们的区别。第一行使用刚展示的方法:在另
一个类的实例上调用静态方法。第二行展示了我们愿意使用的形式:在对象自身上调用实例方法。

ExtendMyData.Avergage(md)  //静态调用形式
md.Average();              //实例调用形式

扩展方法允许你使用第二种形式,即使第一种形式可能是编写这种调用的正常方法。
通过对方法Average的声明做一个小小的改动,就可以使用实例调用形式。需要做的修改是
在参数声明中的类型名前增加关键字this,如下所示。把this关键字加到静态类的静态方法的
第一个参数上,把该方法从类ExtendMyData的常规方法改变为类MyData的扩展方法。现在两种
调用形式都可以使用。

image
扩展方法的重要要求如下。

  • 声明扩展方法的类必须声明为static。
  • 扩展方法本身必须声明为static。
  • 扩展方法必须包含关键字this作为它的一个参数类型,并在后面跟着它扩展的类的
    名称。
    图8-22阐明了扩展方法的结构。

扩展方法的结构

下面的代码展示了一个完整的程序,包括类MyData和声明在类ExtendMyData中的扩展方法
Average。注意方法Average完全如同它是MyData的实例成员那样调用!图8-22阐明了这段代码。
类MyData和ExtendMyData共同起到期望类的作用,带有3个方法。

namespace ExtensionMethods
{sealed class MyData{private double D1,D2,D3;public MyData(double d1,double d2,double d3){D1=d1;D2=d2;D3=d3;}public double Sum(){return D1+D2+D3;}}static class ExtendMyData {public static double Average(this MyData md)  //关键字和类型{return md.Sum()/3;//声明为静态的}}class Program{static void Main(){MyData md=new MyData(3,4,5);Console.WriteLine($"Sum: {md.Sum()}");Console.WriteLine("Average:{0}",md.Average());}}
}

输出结果

Sum : 12
Average :4

命名约定

编写程序时会出现很多名称:类的名称、变量名称、方法名称、属性名称和许多其他名称。
阅读程序时,使用命名约定是为要处理的对象种类提供线索的重要方法。
第7章简单介绍过命名,现在你已经对类有了更多了解,我们可以给出更多细节了。表8-4
列出了3种主要的命名风格,以及它们在.NET程序中常见的使用方式。

常用的标识符命名风格
可维护代码的一个重要支柱就是使用准确、自描述的变量名字(这个策略不太适合类似于
本书的图书、文章和示例代码,因为有其他的考虑)。对于变量名,不能过于追求简洁,否则
“欲速则不达"。

并不是所有人都认同这些命名约定,特别是前缀下划线。有些人认为前缀下划线非常有用,
有些人则认为它非常难看。微软本身对这个问题处理得也不够好。在推荐的命名约定中,微软没
有将前缀下划线作为一种选择,却在代码中大量使用本书将遵循微软官方推荐的命名约定,用Camel大小写作为私有和受保护的字段名称。
关于下划线还有一点要说明的是,它并不常出现在标识符的中间位置,不过事件处理程序除
外,这将在第15章介绍。

相关文章:

  • 【基础算法】枚举(普通枚举、二进制枚举)
  • redis分片集群架构
  • Python60日基础学习打卡Day46
  • 物联网协议之MQTT(二)服务端
  • Qt Test功能及架构
  • Python Cookbook-7.12 在 SQLite 中储存 BLOB
  • 【Java学习笔记】StringBuilder类(重点)
  • 以SMMUv2为例,使用Trace32可视化操作SMMU的常用命令详解
  • stm32内存踩踏一例
  • DeepSeek-R1-0528:开源推理模型的革新与突破
  • AI开发 | 生成式AI在企业软件中的演进形态:从嵌入式到智能体
  • SQL-事务(2025.6.6-2025.6.7学习篇)
  • 零基础玩转物联网-串口转以太网模块如何快速实现与TCP服务器通信
  • Android学习总结-GetX库常见问题和解决方案
  • 安卓基础(Java 和 Gradle 版本)
  • PHP文件包含漏洞详解:原理、利用与防御
  • Android 平台RTSP/RTMP播放器SDK接入说明
  • 2025年- H76-Lc184--55.跳跃游戏(贪心)--Java版
  • 【Java学习笔记】SringBuffer类(重点)
  • compose 组件 ---无ui组件
  • 高端品牌网站建设服务/怎么搭建一个网站
  • 给我看电影全集/广州seo招聘网
  • 济南seo网站排名优化工具/网站及搜索引擎优化建议
  • 网页设计制作是属于什么专业?/惠州seo建站
  • 电子商务网站建设与维护期末答案/今日财经新闻
  • 一级建设造师网站/网盘搜索