C#

结构体

定义

值类型的数据结构,单一变量存储各种数据类型。

创建

struct关键字创建

特点

1.可定义构造函数,不能定义析构函数和无参构造函数

2.不能继承其他结构或者类,但是可以实验一个或者多个接口

3.结构成员不能指定为abstract、virtual、protected

4.可以不使用New操作符进行实例化

结构与类的比较

1.类是引用类型,结构是值类型

2.结构不能声明无参构造函数

3,结构不支持继承

4.结构中声明的字段无法赋予初值

5.结构体的构造函数中,必须为结构体所有字段赋值

枚举

定义

值类型,一组命名整型常量

声明

enum关键字声明

声明语法

1
2
3
4
enum <enum_name>
{
enumeration list
};
  • enum_name指定枚举类型的名称
  • enumeration list是一个用逗号分隔的标识符列表

特点

1.枚举列表中的每个符号代表一个整数值,一个比它前面的符号大的整数值。默认情况下,第一个枚举符号的值是0

2.不能继承和传递继承

定义

以关键字class开始,后跟类的名称。类的主体,包含在一对花括号内。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<access specifier> class  class_name
{
// member variables
<access specifier> <data type> variable1;
<access specifier> <data type> variable2;
...
<access specifier> <data type> variableN;
// member methods
<access specifier> <return type> method1(parameter_list)
{
// method body
}
<access specifier> <return type> method2(parameter_list)
{
// method body
}
...
<access specifier> <return type> methodN(parameter_list)
{
// method body
}
}
注意点
  • 访问标识符<access specifier>指定了对类和成员的访问规则,默认情况下,类的访问标识符是internal,成员的访问标识符是private
  • <data type>指定了变量的类型,<return type>指定了返回方法的数据类型
  • 点运算符链接了对象的名称和成员的名称

构造函数

类的特殊成员函数,当创建类的新对象执行,名称与类的名称完全相同,没有任何返回类型

析构函数

类的特殊成员函数,当类的对象超出范围时执行。

在类的名称前加上一个波浪号(~)作为前缀,不返回值,也不带任何参数

用于在结束程序(关闭文件、释放内存)之前释放资源。

不能继承和重载

静态成员

static关键字定义类成员

用于定义常量,直接调用类而不需要创建类的实例获取

在成员函数或类的定义外部初始化,也可以在类的定义内部初始化静态变量

继承

定义

不需要完全重新编写新的数据成员和成员函数,只需要设计一个新的类,继承了已有的类的成员即可。这个已有的类被称为的基类,这个新的类被称为派生类

创建

1
2
3
4
5
6
7
8
<访问修饰符> class <基类>
{
...
}
class <派生类> : <基类>
{
...
}

多重继承

C# 不支持多重继承。但是可以使用接口来实现多重继承。

多态性

定义

同一个接口,使用不同的实例而执行不同操作

静态多态性

  • 函数重载
  • 运算符重载

函数重载

在同一个范围内对相同的函数名有多个定义,可以是参数列表中的参数类型不同,也可以是参数个数不同,不能只有返回类型不同的函数声明

动态多态性

使用关键字 abstract 创建抽象类,用于提供接口的部分类的实现。当一个派生类继承自该抽象类时,实现即完成。抽象类包含抽象方法,抽象方法可被派生类实现。

注意点
  • 不能创建抽象类的实例
  • 不能在一个抽象类外部声明一个抽象方法
  • 在类定义前面放置关键字 sealed,可以将类声明为密封类。当一个类被声明为 sealed 时,它不能被继承。抽象类不能被声明为 sealed。

虚方法

当有一个定义在类中的函数需要在继承类中实现时,可以使用虚方法

使用关键字 virtual 声明,在不同的继承类中有不同的实现

运算符重载

定义

可以重定义或重载 C# 中内置的运算符,具有特殊名称的函数

关键字 operator 后跟运算符的符号来定义

举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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;
}

public static bool operator == (Box lhs, Box rhs)
{
bool status = false;
if (lhs.length == rhs.length && lhs.height == rhs.height
&& lhs.breadth == rhs.breadth)
{
status = true;
}
return status;
}
public static bool operator !=(Box lhs, Box rhs)
{
bool status = false;
if (lhs.length != rhs.length || lhs.height != rhs.height
|| lhs.breadth != rhs.breadth)
{
status = true;
}
return status;
}
public static bool operator <(Box lhs, Box rhs)
{
bool status = false;
if (lhs.length < rhs.length && lhs.height
< rhs.height && lhs.breadth < rhs.breadth)
{
status = true;
}
return status;
}

public static bool operator >(Box lhs, Box rhs)
{
bool status = false;
if (lhs.length > rhs.length && lhs.height
> rhs.height && lhs.breadth > rhs.breadth)
{
status = true;
}
return status;
}

public static bool operator <=(Box lhs, Box rhs)
{
bool status = false;
if (lhs.length <= rhs.length && lhs.height
<= rhs.height && lhs.breadth <= rhs.breadth)
{
status = true;
}
return status;
}

public static bool operator >=(Box lhs, Box rhs)
{
bool status = false;
if (lhs.length >= rhs.length && lhs.height
>= rhs.height && lhs.breadth >= rhs.breadth)
{
status = true;
}
return status;
}
public override string ToString()
{
return String.Format("({0}, {1}, {2})", length, breadth, height);
}

}

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
Box Box4 = new 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);

// 使用重载的 ToString() 显示两个盒子
Console.WriteLine("Box1: {0}", Box1.ToString());
Console.WriteLine("Box2: {0}", Box2.ToString());

// Box1 的体积
volume = Box1.getVolume();
Console.WriteLine("Box1 的体积: {0}", volume);

// Box2 的体积
volume = Box2.getVolume();
Console.WriteLine("Box2 的体积: {0}", volume);

// 把两个对象相加
Box3 = Box1 + Box2;
Console.WriteLine("Box3: {0}", Box3.ToString());
// Box3 的体积
volume = Box3.getVolume();
Console.WriteLine("Box3 的体积: {0}", volume);

//comparing the boxes
if (Box1 > Box2)
Console.WriteLine("Box1 大于 Box2");
else
Console.WriteLine("Box1 不大于 Box2");
if (Box1 < Box2)
Console.WriteLine("Box1 小于 Box2");
else
Console.WriteLine("Box1 不小于 Box2");
if (Box1 >= Box2)
Console.WriteLine("Box1 大于等于 Box2");
else
Console.WriteLine("Box1 不大于等于 Box2");
if (Box1 <= Box2)
Console.WriteLine("Box1 小于等于 Box2");
else
Console.WriteLine("Box1 不小于等于 Box2");
if (Box1 != Box2)
Console.WriteLine("Box1 不等于 Box2");
else
Console.WriteLine("Box1 等于 Box2");
Box4 = Box3;
if (Box3 == Box4)
Console.WriteLine("Box3 等于 Box4");
else
Console.WriteLine("Box3 不等于 Box4");

Console.ReadKey();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
Box1: (6, 7, 5)
Box2: (12, 13, 10)
Box1 的体积: 210
Box2 的体积: 1560
Box3: (18, 20, 15)
Box3 的体积: 5400
Box1 不大于 Box2
Box1 小于 Box2
Box1 不大于等于 Box2
Box1 小于等于 Box2
Box1 不等于 Box2
Box3 等于 Box4

可重载和不可重载运算符

运算符 描述
+, -, !, ~, ++, – 这些一元运算符只有一个操作数,且可以被重载。
+, -, *, /, % 这些二元运算符带有两个操作数,且可以被重载。
==, !=, <, >, <=, >= 这些比较运算符可以被重载。
&&, || 这些条件逻辑运算符不能被直接重载。
+=, -=, *=, /=, %= 这些赋值运算符不能被重载。
=, ., ?:, ->, new, is, sizeof, typeof 这些运算符不能被重载。

注意点

  • 运算符只能采用值参数,不能采用 ref 或 out 参数
  • 要求成对重载比较运算符。如果重载了==,则也必须重载!=,否则产生编译错误。比较运算符必须返回bool类型的值
  • 不允许重载=运算符,但如果重载例如+运算符,编译器会自动使用+运算符的重载来执行+=运算符的操作

接口

定义

定义了所有类继承接口时应遵循的语法合同。接口定义了语法合同 “是什么” 部分,派生类定义了语法合同 “怎么做” 部分

使得实现接口的类或结构在形式上保持一致

接口本身并不实现任何功能,它只是和声明实现该接口的对象订立一个必须实现哪些行为的契约

声明

使用 interface 关键字声明,与类的声明类似。接口声明默认是 public 的

1
2
3
4
interface IMyInterface
{
void MethodToImplement();
}

接口继承

如果一个接口继承其他接口,那么实现类或结构就需要实现所有接口的成员

命名空间

定义

提供一种让一组名称与其他名称分隔开的方式。在一个命名空间中声明的类的名称与另一个命名空间中声明的相同的类的名称不冲突。

以关键字 namespace 开始,后跟命名空间的名称

1
2
3
4
namespace namespace_name
{
// 代码声明
}

using关键字

using 关键字表明程序使用的是给定命名空间中的名称

使用 using 命名空间指令,这样在使用的时候就不用在前面加上命名空间名称。该指令告诉编译器随后的代码使用了指定命名空间中的名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using System;
using first_space;
using second_space;

namespace first_space
{
class abc
{
public void func()
{
Console.WriteLine("Inside first_space");
}
}
}
namespace second_space
{
class efg
{
public void func()
{
Console.WriteLine("Inside second_space");
}
}
}
class TestClass
{
static void Main(string[] args)
{
abc fc = new abc();
efg sc = new efg();
fc.func();
sc.func();
Console.ReadKey();
}
}

嵌套命名空间

命名空间可以被嵌套,即您可以在一个命名空间内定义另一个命名空间

1
2
3
4
5
6
7
8
namespace namespace_name1 
{
// 代码声明
namespace namespace_name2
{
// 代码声明
}
}

使用点(.)运算符访问嵌套的命名空间的成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
using SomeNameSpace;
using SomeNameSpace.Nested;
namespace SomeNameSpace
{
public class MyClass
{
static void Main()
{
Console.WriteLine("In SomeNameSpace");
Nested.NestedNameSpaceClass.SayHello();
}
}

// 内嵌命名空间
namespace Nested
{
public class NestedNameSpaceClass
{
public static void SayHello()
{
Console.WriteLine("In Nested");
}
}
}
}

异常处理

定义

在程序执行期间出现的问题

提供了一种把程序控制权从某个部分转移到另一个部分的方式

关键字:trycatchfinallythrow

  • try:一个 try 块标识了一个将被激活的特定的异常的代码块。后跟一个或多个 catch 块。
  • catch:程序通过异常处理程序捕获异常。catch 关键字表示异常的捕获。
  • finally:finally 块用于执行给定的语句,不管异常是否被抛出都会执行。例如,如果您打开一个文件,不管是否出现异常文件都要被关闭。
  • throw:当问题出现时,程序抛出一个异常。使用 throw 关键字来完成。

语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
try
{
// 引起异常的语句
}
catch( ExceptionName e1 )
{
// 错误处理代码
}
catch( ExceptionName e2 )
{
// 错误处理代码
}
catch( ExceptionName eN )
{
// 错误处理代码
}
finally
{
// 要执行的语句
}

异常类

C# 中的异常类主要是直接或间接地派生于 System.Exception

System.ApplicationException 类支持由应用程序生成的异常。所以程序员定义的异常都应派生自该类。

System.SystemException 类是所有预定义的系统异常的基类。

异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;
namespace ErrorHandlingApplication
{
class DivNumbers
{
int result;
DivNumbers()
{
result = 0;
}
public void division(int num1, int num2)
{
try
{
result = num1 / num2;
}
catch (DivideByZeroException e)
{
Console.WriteLine("Exception caught: {0}", e);
}
finally
{
Console.WriteLine("Result: {0}", result);
}

}
static void Main(string[] args)
{
DivNumbers d = new DivNumbers();
d.division(25, 0);
Console.ReadKey();
}
}
}
1
2
3
Exception caught: System.DivideByZeroException: 尝试除以零。
在 finalReview.DivNumbers.division(Int32 num1, Int32 num2) 位置 D:\QQ\1766522495\.net应用开发技术\C#\finalReview\finalReview\Program.cs:行号 17
Result: 0

创建用户自定义异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using System;
namespace UserDefinedException
{
class TestTemperature
{
static void Main(string[] args)
{
Temperature temp = new Temperature();
try
{
temp.showTemp();
}
catch(TempIsZeroException e)
{
Console.WriteLine("TempIsZeroException: {0}", e.Message);
}
Console.ReadKey();
}
}
}
public class TempIsZeroException: ApplicationException
{
public TempIsZeroException(string message): base(message)
{
}
}
public class Temperature
{
int temperature = 0;
public void showTemp()
{
if(temperature == 0)
{
throw (new TempIsZeroException("Zero Temperature found"));
}
else
{
Console.WriteLine("Temperature: {0}", temperature);
}
}
}
1
TempIsZeroException: Zero Temperature found

文件的输入与输出

定义

一个存储在磁盘中带有指定名称和目录路径的数据集合

当打开文件进行读写时,它变成一个 ,从根本上说,流是通过通信路径传递的字节序列

两个主要的流:输入流输出流

输入流用于从文件读取数据(读操作)

输出流用于向文件写入数据(写操作)

I/O类 描述
BinaryReader 从二进制流读取原始数据。
BinaryWriter 以二进制格式写入原始数据。
BufferedStream 字节流的临时存储。
Directory 有助于操作目录结构。
DirectoryInfo 用于对目录执行操作。
DriveInfo 提供驱动器的信息。
File 有助于处理文件。
FileInfo 用于对文件执行操作。
FileStream 用于文件中任何位置的读写。
MemoryStream 用于随机访问存储在内存中的数据流。
Path 对路径信息执行操作。
StreamReader 用于从字节流中读取字符。
StreamWriter 用于向一个流中写入字符。
StringReader 用于读取字符串缓冲区。
StringWriter 用于写入字符串缓冲区。

FileStream类

创建一个 FileStream 对象来创建一个新的文件,或打开一个已有的文件

1
2
FileStream <object_name> = new FileStream( <file_name>,
<FileMode Enumerator>, <FileAccess Enumerator>, <FileShare Enumerator>);
参数

FileMode:枚举定义了各种打开文件的方法

  • Append:打开一个已有的文件,并将光标放置在文件的末尾。如果文件不存在,则创建文件。
  • Create:创建一个新的文件。如果文件已存在,则删除旧文件,然后创建新文件。
  • CreateNew:指定操作系统应创建一个新的文件。如果文件已存在,则抛出异常。
  • Open:打开一个已有的文件。如果文件不存在,则抛出异常。
  • OpenOrCreate:指定操作系统应打开一个已有的文件。如果文件不存在,则用指定的名称创建一个新的文件打开。
  • Truncate:打开一个已有的文件,文件一旦打开,就将被截断为零字节大小。然后我们可以向文件写入全新的数据,但是保留文件的初始创建日期。如果文件不存在,则抛出异常。

FileAccess:枚举的成员有:ReadReadWriteWrite

FileShare

  • Inheritable:允许文件句柄可由子进程继承。Win32 不直接支持此功能。
  • None:谢绝共享当前文件。文件关闭前,打开该文件的任何请求(由此进程或另一进程发出的请求)都将失败。
  • Read:允许随后打开文件读取。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取的请求(由此进程或另一进程发出的请求)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。
  • ReadWrite:允许随后打开文件读取或写入。如果未指定此标志,则文件关闭前,任何打开该文件以进行读取或写入的请求(由此进程或另一进程发出)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。
  • Write:允许随后打开文件写入。如果未指定此标志,则文件关闭前,任何打开该文件以进行写入的请求(由此进程或另一进过程发出的请求)都将失败。但是,即使指定了此标志,仍可能需要附加权限才能够访问该文件。
  • Delete:允许随后删除文件。