(五)CSharp-类

news/2024/10/30 15:25:37/

一、类

1、类的定义和类成员

程序的数据和功能被组织为逻辑上相关的数据项和函数的封装集合,并称为类。
类是一个能存储数据并执行代码的数据结构。它包含数据成员和函数成员。

表-类成员的类型

数据成员存储数据函数成员执行代码
字段、常量方法、属性、构造函数、析构函数 运算符、索引器、事件
//显式和隐式字段初始化
class MyClass
{
int F1; //初始化为 0 - 值类型
string F2; //初始化为 null - 引用类型
int F3 = 25; //初始化为 25
string F4 = "abcd"; //初始化为 “abcd”
}

2、为数据分配内存

类的实例是引用类型,所以需要使用 new 运算符实例化:

  • new 运算符为任意指定类型的实例分配并初始化内存。它依据类型的不同从栈或堆里分配。
  • 如果将内存分配给一个引用类型,则对象创建表达式返回一个引用,指向在堆中被分配并初始化的对象实例。

3、属性

1)只读和只写属性

  • 只有 get 访问器的属性称为只读属性。只读属性能够安全地将一个数据项从类或类的实例中传出,而不必让调用者修改属性值。
  • 只有 set 访问器的属性称为只写属性。只写属性很少见,因为它们几乎没有实际用途。
  • 两个访问器中至少有一个必须定义,否则编译会产生一条错误消息。

2)属性与公有字段的区别

  • 属性是函数成员而不是数据成员,允许你处理输入和输出,而公有字段不行。
  • 属性可以只读或只写,而字段不行。
  • 编译后的变量和编译后的属性语义不同

C# 图解教程-7.10.7 属性与公有字段》书上附加内容:

如果要发布一个由其他代码引用的程序集,那么第三点将会带来一些影响。例如,有的时候开发人员可能想用共有字段代替属性,因为如果以后需要为字段的数据增加处理逻辑的话,可以再把字段改为属性。这没错,但是如果那样修改的话,所有访问这个字段的其他程序集都需要重新编译,因为字段和属性在编译后的语义不一样。另外,如果实现的是属性,那么只需要修改属性的实现,而无须重新编译访问它的其他程序集。

我需要提供一些代码例子来加强理解:

如果程序员对某一情况最初始的想法是只使用字段:

//程序集Stuclass Student{public int Id;}被其他程序集ABC...访问引用
class Other
{
public Other()
{
Student stu = new Student();
stu.Id = 2;//此处是字段
}
}

但是产品经理说,下版本有这样的需求:Student 的 Id 不能有负值。哦豁,如果按照以上的代码来设计,那估计其他访问Stu的所有程序集都必须做判断的逻辑处理。如果只是把Id字段改为属性类型,同样也得需要重新编译其他所有访问 Stu 的程序集才能生效,因为它们访问的类型都必须保持一致。否则,会报错。

所以,最开始就应该这么做:

   //程序集Stu 版本1class Student{private int id;public int Id{get { return id; }set{id = vvalue;}}}//程序集Stu 版本2
class Student{private int id;public int Id{get { return id; }set{if (id > 0)id = value;elseid = 0;}}}其他所有程序集访问Stu
class Other
{
public Other()
{
Student stu = new Student();
stu.Id = 2;//此处是属性,对版本1和版本和2都能访问
}
}

3)自动实现属性(简称自动属性)

  • 不声明后备字段——编译器根据属性的类型分配存储。
  • 不能提供访问器的方法体——它们必须被简单地声明为分号,get 担当简单的内存读,set 担当简单的写。但是因为无法访问自动属性的方法体,所以在使用自动属性时调试代码通常会更更加困难。

4)静态属性

静态属性的访问器和所有静态成员一样,具有以下特点:

  • 不能访问类的实例成员,但能被实例成员访问。
  • 不管类是否有实例,它们都是存在的。
  • 在类的内部,可以仅使用名称来引用静态属性。
  • 在类的外部,可以通过类名或者使用 using static 结构来引用静态属性。

4、其他静态成员类型

可以声明为 static 的类成员类型做了勾选标记

表-可以声明为静态的类成员类型

数据成员(存储数据)函数成员(执行代码)
✅字段✅方法
✅类型✅属性
🚫常量✅构造函数
✅运算符
🚫索引器
✅事件

5、静态构造函数

静态构造函数初始化类的静态字段

静态构造函数与实例构造函数的区别:

  • 1)静态构造函数声明中使用 static 关键字
  • 2)类只能有一个静态构造函数,而且不能带参数
  • 3)静态构造函数不能有访问修饰符

6、屏蔽基类的成员(隐藏)

  • 屏蔽基类的成员(数据成员,静态成员,函数成员),可使用 new 修饰符。
  • 函数成员,签名由名称和参数列表组成,不包括返回类型。

7、抽象成员

虚成员抽象成员
关键字virtualabstract
实现体有实现体没有实现体,被分号取代
在派生类中被覆写能被覆写,使用 override必须被覆写,使用 override
成员的类型方法属性事件索引器方法属性事件索引器

二、弱引用

实例化一个类或结构时,只要有代码引用它,就会形成强引用。
根据例子来理解强引用

MyClass myClassVariable = new MyClass();

myClassVariable 引用该类的对象,那么只要 myClassVariable 在作用域内,就存在对 MyClass 对象的强引用。

使用弱引用的情况:
强引用意味着垃圾回收器不会清理 MyClass 对象使用的内存。如果 MyClass 对象很大,并且不经常访问,就可以创建对象的弱引用。
弱引用允许创建和使用对象,但是垃圾回收器运行时,就会回收对象并释放内存
弱引用是使用了系统提供的 WeakReference 类创建的。

使用弱引用的例子:

  class MathTest{public int Value;public int GetSquare(){return Value * Value;}public static int GetSquareOf(int x){return x * x;}public static double GetPi(){return 3.14159;}}class Program{static void Main(string[] args){WeakReference mathReference = new WeakReference(new MathTest());MathTest math;//检查确保MathTest对象未被回收//若IsAlive为true,就从目标属性得到MathTest对象的引用if (mathReference.IsAlive){math = mathReference.Target as MathTest;math.Value = 30;Console.WriteLine("Value field of math variable contains " + math.Value);Console.WriteLine("Square of 30 is " + math.GetSquare());}else{Console.WriteLine("Reference is not available.");}//调用垃圾回收器GC.Collect();//再次尝试获取MathTest对象if (mathReference.IsAlive){math = mathReference.Target as MathTest;}else{//此处说明MathTest对象已被回收。//如果想要再使用MathTest对象,就必须实例化一个新的MathTest对象。Console.WriteLine("Reference is not available.");}Console.ReadKey();}}

三、匿名类

匿名类型只是一个继承自 Object 且没有名称的类。

var captain = new { FirstName = "Leonard", MiddleName = "", LastName = "McCoy" };

如果通过另一个对象来设置初始值:

 var person = new { FirstName = "Leonard", MiddleName = "", LastName = "McCoy" };var captain = new { person.FirstName, person.MiddleName, person.LastName  };

四、部分类

partial 关键字允许把类、结构、方法或接口放在多个文件中。

分部方法分为两部分:

  • 定义分部方法
  • 实现分部方法

分部方法定义声明和实现声明的签名和返回类型必须匹配。签名和返回类型有如下特征:

  • ==返回类型必须是 void ==。
  • 签名不能包括访问修饰符,这使分部方法是隐式私有的
  • 在定义声明和实现声明中都必须包含上下文关键字 partial,并且直接放在关键字 void 之前。
//文件A:partial class MyClass{partial void PrintSum(int x, int y);public void Add(int x, int y){PrintSum(x, y);}}//文件B:partial class MyClass{partial void PrintSum(int x, int y){Console.WriteLine("Sum is {0}", x + y);}}

五、静态类

如果类只包含静态的方法和属性,该类就是静态的。

  static class StaticUtilities{public static void HelperMethod(){}}class Program{static void Main(string[] args){StaticUtilities.HelperMethod();Console.ReadKey();}}

六、Object 类

所有的 .NET 类都派生自 System.Object。如果在自定义类时没有指定基类,编译器就会自动假定整个类派生自 Object。

System.Object() 方法

我在这里把书上的部分内容,进行排版,并做成一个表单的形式来显示该部分内容:

方法描述
ToString()是获取对象的字符串表示的一种便捷方式。⚪当只需要快速获取对象的内容,以进行调试时,就可以使用这个方法。⚪在数据的格式化方面,它几乎没有提供选择:例如,在原则上日期可以表示为许多不同的格式,但 DateTime.ToString() 没有在这方面提供任何选择。如果需要更复杂的字符串表示。例如,考虑用户的格式化首选项或区域性(区域),就应实现 IFormattable 接口。
GetHashCode()如果对象放在名为映射(也称为散列表或字典)的数据结构中,就可以使用整个方法。处理这些结构的类使用方法确定把对象放在结构的什么地方。如果希望把类用作字典的一个键,就需要重写 GetHashCode() 方法。实现该方法重载的方式有一些相当严格的限制。
Equals()(两个版本) 和 ReferenceEquals()主要有3个用于比较对象相等性的不同方法,这说明 .NET Framework 在比较相等性方面有相当复杂的模式。这3个方法和比较运算符 “ == ” 在使用方式上有微妙的区别。而且,在重写带一个参数的虚 Equals() 方法时也有一些限制,因为 System。Collections 名称空间中的一些基类要调用该方法,并希望它以特定的方式执行。
Finalize()它最接近 C++ 风格的析构函数,在引用对象作为垃圾被回收以清理资源时调用它。 Object 中实现的 Finalize() 方法实际上什么也没有做,因而被垃圾回收器忽略。如果对象拥有对未托管资源的引用,则在该对象删除时,就需要删除这些引用,此时一般要重写 Finalize()。垃圾回集器不能直接删除这些对未托管资源的引用,因为它只负责托管的资源,于是它只能依赖用户提供的 Finalize()。
GetType()这个方法返回从 System.Type 派生的类的一个实例。这个对象可以提供对象成员所属类的更多信息,包括基本类型、方法、属性等。System.Type 还提供了 .NET 的反射技术的入口点。
MemberwiseClone()它复制对象,并返回对副本的一个引用(对于值类型,就是一个装箱的引用)。注意,得到的副本是一个浅表复制,即它复制了类的所有值类型。如果类包含内嵌的引用,就只复制引用,而不复制引用的对象。这个方法是受保护的。所以不能用于复制外部的对象。该方法不是虚方法,所以不能重写它的实现代码。

http://www.ppmy.cn/news/282016.html

相关文章

linux(信号发送后)

目录: 1.引入什么是合适的时候 2.内核态和用户态 3.信号的处理 4.sigaction函数 -------------------------------------------------------------------------------------------------------------------------------- 1.引入什么是合适的时候 2.信号什么时候被处…

一文学会MoveIt Setup Assistant搭建moveit2机械臂模型

文章目录 前言一、MoveIt Setup Assistant 是什么?二、搭建步骤拉取相关repo创建项目文档编辑moveit_description文件夹编辑moveit_config文件夹 MoveIt Setup Assistant 配置Launch moveit_setup_assistant配置干涉关系配置planning groups配置ros2 controller配置…

无线充电宝有用吗?有没有好的无线充电宝推荐

对于充电宝的便利性,我相信大家也是知晓的,平时出门在外,当手机没电的时候,你第一个想起的应该就是充电宝了吧,充电宝不仅可以有效地解决手机没电续电,而且最主要的是携带方便,如今充电宝也是越…

PD QC快充诱骗取电方案:输出9V12V15V20V

手机快充充电器或充电宝,在没有与手机通讯时,快充充电器相当于普通的充电器只输出5V电压,要想得到充电器的9V/12V等电压,可以使用快充取电电路。 或者也可以使用电子元件来搭建诱骗电路,但是和专用的取电芯片方案相比&…

快充协议(QC/PD/PE)

充电按用途可分为:车充,墙冲,无线充和充电宝(移动电源);按接口可分为Micro-USB, USB-A or B, Type-C和Lightning(Apple); 按充电快慢可分为BC1.2,USB/Lightning标准&…

快充协议(QC/PD/PE)及标准

快充协议(QC/PD/PE)及标准 充电按用途可分为:车充,墙冲,无线充和充电宝(移动电源);按接口可分为Micro-USB, USB-A or B, Type-C和Lightning(Apple); 按充电快…

快充芯片IP5328P的寄存器数据读写[用于DIY数显快充充电宝]

【本帖DIY因为有一定的危险性,非专业人员请勿自行尝试】 【如有侵权 联系删除】 IP5328P是一款最大18W的快充芯片,主要用于快充充电宝的产品,基本支持市面上绝大部分主流的快充协议。 因为能看到本帖的想必都是对这个芯片很了解了&#xf…

pd快充的电压和电流_实测绿联PD直充、充电宝、车充,全方位快充的神仙体验...

越来越多的智能产品都支持快充了,苹果在iPhone 8开始也加入了快充的行列,自从有了PD快充套装之后,充电效率得到了不少提升,30分钟充电50%的体验,大多数人体验后就很难再回得去了。 苹果官方正式宣布开放了Type-C转Lightning的授权,让果粉享受PD快充有了更多的选择, 国内…