1.C#类(Class)
类:对某一类事物的描述;描述事物时一般只关注两方面,事物的属性和行为(功能/方法)。
构成类的方法和变量成为类的成员。
14.1.类的定义
访问修饰符 class 类名称{
类主体;
}
例如:
public class cat
{
//成员属性
string name;
int age;
string sex;
//成员方法
public string call()
{
//方法体
Console.WriteLine("喵喵喵喵~~~~");
}
}
1.1.类的成员函数和封装
成员函数:是在类定义中有他的定义或原型的函数,就像其他变量一样。是类的成员,可以在类的任何对象上操作,且能访问该对象的类的所有成员。
封装:将类的成员属性私有化,对外提公有的成员方法来访问属性。
1.2.类的构造函数
构造函数:类的 构造函数 是类的一个特殊的成员函数,当创建类的新对象时执行。
构造函数的名称与类的名称完全相同,它没有任何返回类型。
默认构造函数没有任何参数,你可以创建一个带有参数的构造函数,被称参数化构造函数,用来在创建对象的同时给对象赋初值。
class Line
{
private double length; // 线条的长度
public Line(double len) // 参数化构造函数
{
Console.WriteLine("对象已创建,length = {0}", len);
length = len;
}
public void setLength( double len )
{
length = len;
}
public double getLength()
{
return length;
}
static void Main(string[] args)
{
Line line = new Line(10.0);
Console.WriteLine("线条的长度: {0}", line.getLength());
// 设置线条长度
line.setLength(6.0);
Console.WriteLine("线条的长度: {0}", line.getLength());
Console.ReadKey();
}
}
1.3.C#中的析构函数
析构函数:类的析构函数是类的一个特殊成员函数,当类的对象超出范围时执行。
析构函数的名称是在类的名称钱夹~符号,他没有返回值,也没有任何参数。
析构函数用于在结束程序(比如关闭文件、释放内存等)之前释放资源。析构函数不能继承或重载。
class Line
{
private double length; // 线条的长度
public Line() // 构造函数
{
Console.WriteLine("对象已创建");
}
~Line() //析构函数
{
Console.WriteLine("对象已删除");
}
public void setLength( double len )
{
length = len;
}
public double getLength()
{
return length;
}
static void Main(string[] args)
{
Line line = new Line();
// 设置线条长度
line.setLength(6.0);
Console.WriteLine("线条的长度: {0}", line.getLength());
}
}
1.4.C#类的静态成员
可以使用static关键字将类中的成员变量和方法定义成静态的成员变量和方法,当我们声明一个类成员为静态时,意味着无论有多少个类的对象被创建,只会有一个该静态成员的副本。
关键字static意味着类中只有一个该成员的实例。静态变量用于定义常量,因为他们的值可以通过直接调用类而不需要创建类的实例来获取。静态变量可在成员函数或类的定义外部进行初始化,也可以在内部初始化。
当一个成员函数声明为static时,这样的函数只能访问静态变量,静态函数在对象被创建之前就已经存在。
2.C#继承
继承:是面向对象程序设计中最重要的概念之一。继承允许我们根据一个类来定义另一个类,这使得创建和维护应用程序变得更容易,有利于代码复用。
当创建一个类时,程序员不需要完全编写新的数据成员和成员函数,只需要设计一个新的类,继承了已有的类的成员即可。
这个类被称为基类(父类),新的类被称为派生类。
一个类可以派生多个类或接口,这意味着它可以从多个基类或接口继承数据和函数。
创建派生类语法如下:
<访问修饰符> class <基类>
{
...
}
class <派生类> : <基类>
{
...
}
基类的初始化:派生类集成了基类的成员变量和成员方法。因此父类对象应在子类对象创建前被创建。可以在成员初始化列表中进行父类的初始化。
2.1.C#多重继承
多继承:一个子类可以继承多个父类的属性和方法,但是每个父类只能继承一次。
例如:一个类可以同时继承动物类和植物类,但不能同时继承两个动物类。
多重继承:一个子类可以同时继承多个父类的属性和方法,每个父类可以集成多次。
例如:一个类可以同时继承动物类和哺乳动物类,因为哺乳动物类也是动物类的子类。
总的来说:多重继承是多继承的一种特殊情况,它允许一个子类同时继承多个父类,并且每个父类可以继承多次。但是,多重继承会增加代码的复杂度和维护难度,使用需谨慎。
C#不支持多重继承。
可以使用接口来实现多重继承。
3.C#多态性
多态:是同一个行为具有多个不同表现形式或形态的能力。
多态性意味着有多重形式。在面向对象编程范式中,多态往往表现为“一个接口,多个功能”。
多态性可以使静态的或动态的。
静态多态性中,函数的响应是在编译时发生的。
在动态多态性中,函数的响应是在运行时发生的。
在C#中,每个类型都是多态的,因为包括用户定义类型在内的所有类型都继承自Object。
多态就是哦同一个接口,使用不同的实力而执行不同的操作。同一个事件发生在不同的对象上会产生不同的结果。
3.1.静态多态性
在编译时,函数和对象的链接机制被称为早期绑定,也被称为静态绑定。
C#提供了两种技术来实现静态多态性:函数重载和运算符重载。
3.1.1.函数重载
可以在同一个范围内对相同的函数名有多个定义,函数名相同,但参数列表不同(可以是参数类型不同或参数个数不同)。
注意:不能重载只有返回类型不同的函数声明。
例如:下面是参数个数不同的方法重载
//add函数重载
class Test
{
public int add(int a,int b)
{
return a + b;
}
public int add(int a, int b,int c)
{
return a + b + c;
}
}
下面是参数个数相同但参数类型不同的方法重载示例:
class Test
{
public int write(int i)
{
Console.WriteLine("输出整形:{0}",i);
}
public double write(double d)
{
Console.WriteLine("输出浮点型:{0}"d);
}
public string write(string s)
{
Console.WriteLine("输出字符串:{0}",s);
}
}
3.1.2.运算符重载
可以重定义或重载C#中内置的运算符。
程序员也可以使用用户自定义的运算符。重载运算符是具有特殊名称的函数,是通过关键字operator后跟运算符的符号来定义的。与其他函数一样,重载运算符有返回类型和参数列表。
using System;
namespace OperatorOvlApplication
{
class Box
{
private double length; // 长度
private double breadth; // 宽度
private double height; // 高度
public double getVolume()
{
return length * breadth * height;
}
public void setLength( double len )
{
length = len;
}
public void setBreadth( double bre )
{
breadth = bre;
}
public void setHeight( double hei )
{
height = hei;
}
// 重载 + 运算符来把两个 Box 对象相加
public static Box operator+ (Box b, Box c)
{
Box box = new Box();
box.length = b.length + c.length;
box.breadth = b.breadth + c.breadth;
box.height = b.height + c.height;
return box;
}
}
class Tester
{
static void Main(string[] args)
{
Box Box1 = new Box(); // 声明 Box1,类型为 Box
Box Box2 = new Box(); // 声明 Box2,类型为 Box
Box Box3 = new Box(); // 声明 Box3,类型为 Box
double volume = 0.0; // 体积
// Box1 详述
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// Box2 详述
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// Box1 的体积
volume = Box1.getVolume();
Console.WriteLine("Box1 的体积: {0}", volume);
// Box2 的体积
volume = Box2.getVolume();
Console.WriteLine("Box2 的体积: {0}", volume);
// 把两个对象相加
Box3 = Box1 + Box2;
// Box3 的体积
volume = Box3.getVolume();
Console.WriteLine("Box3 的体积: {0}", volume);
Console.ReadKey();
}
}
}
可重载运算符和不可重载运算符
运算符 | 描述说明 |
~、!、++、-- | 这些一元运算符只有一个操作数,且可以被重载。 |
+、-、*、/、% | 这些二元运算符带有两个操作数,且可以被重载。 |
==、!=、<、>、<=、>= | 比较运算符可以被重载。 |
&&、|| | 条件逻辑运算符不能被直接重载。 |
+=、-=、*=、/=、%= | 赋值运算符不能被重载 |
=、.、?、->、new、is、sizeof、typeof | 不能被重载 |
3.2.动态多态性
C#允许使用关键字abstract创建抽象类,用于提供接口的部分类的实现,当一个派生类继承自该抽象类,实现即完成。
抽象类包含抽象方法,抽象方法可以被派生类实现,实现给你个专业的功能。
注意:
- 不能创建抽象类的实例;
- 抽象方法必须在抽象类中声明;
- 通过在类前面放置关键字sealed,可以将类声明为密封类。一个被声明为sealed的类,不可以被继承。因此抽象类不能被声明为sealed。
//抽象类
abstract class Shape
{
abstract public int area();
}
class Rectangle: Shape
{
private int length;
private int width;
public Rectangle( int a=0, int b=0)
{
length = a;
width = b;
}
public override int area ()
{
Console.WriteLine("Rectangle 类的面积:");
return (width * length);
}
}
class RectangleTester
{
static void Main(string[] args)
{
Rectangle r = new Rectangle(10, 7);
double a = r.area();
Console.WriteLine("面积: {0}",a);
Console.ReadKey();
}
}
4.C#接口(interface)
接口中定义了所有类实现接口时应当遵循的事情。
接口定义了属性、方法和事件,这些都是接口的成员。接口只包含了成员的声明。成员的定义需要在实现类中实现。接口提供了派生类应遵循的标准接口。
抽象类在某种程度上类似于接口,但是,他们大多只是用在当只有少数方法有基类声明或派生类实现的时候。
接口本身不实现任何功能,它只是声明了派生类索要实现的事务。
接口定义使用关键字interface定义。接口命名通常以字母"I"开头。
interface IMyInterface
{
//成员方法
void MethodName(参数列表);
}
//实现类
class InterfaceImplementer : IMyInterface
{
//重写方法
......
}
5.C#命名空间(NameSpace)
命名空间的设计目的是为了提供让一组名称和其他名称分隔开的方式。在一个命名空间中声明的类的名称与另一个命名空间中声明相同的类的名称不冲突。
命名空间的定义使用关键字namespace
格式: namespace 名称{}
为调用支持命名空间版本的函数和变量,会把命名空间的名称至于前面以 . 的方式调用。
using关键字:表明程序使用的是给定命名空间的名称。
用法:
- 引入命名空间;
- using static指令:指定无需指定类型名称即可访问其静态成员的类型
- 起别名:例如:using Project = PC.MyCompany.Project
- using语句:将实例与代码绑定
using (Font font3 = new Font("Arial", 10.0f), font4 = new Font("Arial", 10.0f)) { // Use font3 and font4. } //代码段结束时,自动调用font3和font4的Dispose方法,释放实例
6.C#预处理指令
预处理指令指导编译器在实际编译开始之前对信息进行预处理。
所有的预处理指令都已#开始。且在一行上,只有空白字符可以出现在预处理指令之前。预处理指令不是语句,所以他们不是以分号结束的。
C#编译器没有一个单独的预处理器,但指令被处理时就像有一个大度的预处理器一样。
C#预处理指令用于在条件编译中起作用。
一个预处理指令必须是该行商的位移指令。
预处理指令 | 描述 |
#defind | 用于定义一系列成为符号的字符。 |
#undef | 用于取消定义符号。 |
#if | 用于测试符号是否为真。 |
#else | 用于创建复合条件指令,与#if一起使用。 |
#elif | 用于创建符合条件指令。 |
#endif | 指定一个条件指令的结束。 |
#line | 它可以让你修改编译器的行数以及输出错误和警告的文件名。 |
#error | 允许从代码的指定位置生成一个错误 |
#warning | 允许从代码的指定位置生成一级警告。 |
#region | 让你在使用vsCodeEditor的大纲特性时,指定一个可展开或折叠的代码块。 |
#endregion | 标识这#region块的结束。 |
6.C#正则表达式
正则表达式是一种匹配输入文本的模式。
.net框架提供了允许这种陪陪的正则表达式引擎。、
正则表达式由一个或多个字符、运算符和结构组成。
负责字符串的匹配处理(一般用于验证字符串格式)
正则表达式本身也是一个字符串
7.C#异常处理
异常是在程序执行期间出现的问题。C#中的异常是对程序运行时出现的特殊情况的一种响应。
异常提供了一种把程序控制权从某个部分转移到另一个部分的方式。C#异常处理时建立在四个关键词之上,分别是try、catch、finally、throw.。
- try:一个try块标识了一个将被激活的特定的异常的代码块。后面可以跟多个catch块。
- catch:程序通过异常处理程序捕获异常。catch关键字表示异常的捕获。
- finally:finally块用于执行给定的语句,不管程序是否抛出异常都会被执行。但一个try块最多只能出现一次。
- throw:当问题出现时,程序抛出一个异常,用throw来完成。
7.1..C#中的异常类
C#中异常是用类来表示的。C#中的异常类主要是直接或间接的派生于System.Exception类。
System.ApplicationException:支持由应用程序生成的异常。所以程序员自定义的异常类都应该派生于此。
System.SystenException:所有预定义的系统西昌类的基类。
异常类 | 描述 |
System.IO.IOException | 处理I/O错误。 |
System.IndexOutOfRangeException | 数组下标越界异常。 |
System.ArrayTypeMismatchException | 数组类型不匹配异常。 |
System.NullReferenceException | 处理当依存一个空对象时发生的异常。 |
System.DivideByZeroException | 当除数为零时发生的异常。 |
System.OutOfMemoryException | 处理内存空间不足时发发生的异常。 |
System.StackOverflowException | 处理栈溢出异常。 |
System.InvalidCastException | 处理类型转换异常。 |
C#以try和catch块的形式提供了一种结构化的异常处理方案。使用这些块将核心程序语句与错误处理语句分离开。
try
{
//try块
有可能出现异常的代码片段;
}
catch(XXXException e)
{
//catch块
解决异常的代码片段(catch块跟在try块之后,
用于捕获并解决异常,catch块可以出现多次)
}
finally
{
//finally块(并不是必需的)
不管是否出现异常,总会执行代码块(通常我们使用finally语句作为程序的收尾工作)
}
自定义异常:用户自定义异常类时派生自ApplicationException类。
8.C#中文件的输入与输出
一个文件是一个存储在磁盘中带有指定名称和目录路径的数据集合,。当打开文件进行读写操作时,他变成一个 流。
从根本上说,流 是通过通信路径传递的字节序列。
流可以分为输入流和输出流。
输入流:用于从文件中读取数据(读操作);
输出流:用于想文件中写入数据(写操作)。
8.1.C#中I/O类
System.IO 命名空间有各种不同的类,用于执行各种文件操作,例如:创建和删除文件、读取或写入文件、关闭文件等。
I/O类 | 描述 |
---|---|
BinaryReader | 从二进制流读取原始数据。 |
BinaryWriter | 以二进制格式写入原始数据。 |
BufferedStream | 字节流的临时存储。 |
Directory | 有助于操作目录结构。 |
DirectoryInfo | 用于对目录执行操作。 |
DriveInfo | 提供驱动器信息。 |
File | 有助于处理文件。 |
FileInfo | 用于对文件执行操作。 |
FileStream | 用于文件中任何位置的读写。 |
MemoryStream | 用于随机访问存储在内存中的数据流。 |
Path | 对路径信息执行操作。 |
StreamReader | 用于从字节流中读取数据。 |
StreamWriter | 用于向一个流中写入字符。 |
StringReader | 用于读取字符串缓冲区。 |
StringWriter | 用于写入字符串缓冲区。 |
8.2.FileStream类
System.IO命名空间中的FileStream类有助于文件的读写与关闭。该类派生自抽象类Stream。
创建一个FileStream对象来创建一个新的文件,或打开一个现有文件,创建语法如下:
FileStream <object_name> = new FileStream( <file_name>,
<FileMode Enumerator>, <FileAccess Enumerator>, <FileShare Enumerator>);
参数 | 描述 |
---|---|
FileMode | FileMode枚举类型,用于指定打开文件的模式。
|
FileAccess | FileAccess用于指定文件的访问方式:
|
FileShare | FileShare用于指定文件的共享方式:
|
注意:在使用FileMode时,通常还需要指定FileAccess和FileShare参数来确定文件的访问权限和共享方式。
例如:下列代码将以只读方式打开文件并允许其他进程以只读方式打开该文件。
using System.IO;
FileStream fileStream = new FileStream("example.txt",FileMode.Open,FileAccess.Read,FileShare.Read);
8.3.C# Windows文件系统的操作
C#允许使用各种目录和文件的相关类来操作目录和文件,比如DirectoryInfo类h和FileInfo类。
8.3.1.DirectoryInfo类
DirectoryInfo类派生自FileSystemInfo类。他提供了各种用于创建、移动、浏览目录和子目录的方法。该类不能被继承。
DirectoryInfo类常用的一些方法和属性:
属性:
- Attributes:获取当前目录的属性。
- CreationTime:获取当前文件夹的创建时间。
- Exists:判断文件夹是否存在。
- FullName:获取当前文件夹的完整路径。
- Name:获取当前文件夹的名称。
- Parent:获取当前文件夹的付文件夹。
- LastWriteTime:获取当前文件夹的最后修改时间。
- LastAccessTime获取当前文件夹的最后访问时间。
方法:
- Create:创建文件夹。
- Delete:删除文件夹。
- GetDirectories:获取文件夹中的所有子文件夹。
- getFiles:获取文件夹中的所有文件。
- MoveTo:将文件夹移动到指定位置。
- CopyTo:将文件夹复制到指定位置。
- GetFileSystemInfos:获取文件夹中的所有文件和子文件夹。
- Refresh:刷新文件夹信息。
- ToString:将文件夹转换为字符串表示形式。
8.3.2. FileInfo类
FileInfo类派生自FileSystemIn类。它是C#中用于操作文件的类,它提供了许多属性和方法来获取和操作文件的信息。
FileInfo类中的常用属性和方法:
属性:
- Name:获取获文件名(包括扩展名)。
- FullName:获取文件的完整路径(包括文件名和扩展名)。
- Extension:获取文件的扩展名。
- Length:获取文件的大小。(以字节为单位)
- CreationTime:获取文件的创建时间。
- LastWriteTime:获取文件的最后修改时间。
- LastAccessTime:获取文件的最后访问时间。
方法:
- Delete():删除文件。
- MoveTo(string destFileName):将文件移动到指定的目录或重命名文件下。
- CopyTo(string destFileame):将文件复制到指定的目录。
- OpenRead():打开文件已进行读取。
- OpenWrite():打开文件以进行写入。
- Create():创建一个新文件。
- Exists():判断文件是否存在。
- GetAccessControl():获取文件的访问控制列表。
- SetAccessControl():设置文件的访问控制列表。
- GetDirectories():获取文件所在目录的子目录列表。
- GetFiles():获取文件所在目录的文件列表。
- GetFileSystemInfos():获取文件所在目录的文件和子目录列表。
- ToString():返回文件的路径和名称的字符串表现形式。