0 思维导图
如图 1.1,图片较大建议展开观看。
1 类
类是应用程序的组成部分。一个类是由字段(变量)和方法(函数)的组合而成的。
注:字段和属性在C#中严格来说并不是一个同东西,但是从概念上讲他们是相同的。他们代表了一个类的一些特性。
一个对象是类的一个示例。在运行时,许多对象相互合作来提供一些功能。拿超市来打比方,一个超市有很多人相互合作来为顾客提供服务。每一个雇员都有自己对应的职责。软件就是一样的,雇员之于超市就像类之于应用程序。一个雇员在做他的工作就像一个对象在应用程序中处于运行时。
我们通过如下代码创建一个类:
public class Person
{
}
public 在这里是访问修饰符。它决定了这个类对于其他类来说是否可见。
现在来为这个类增加一个字段和方法:
public class Person
{
public string Name;
public void Introduce()
{
Console.WriteLine("My Name is "+ Name);
}
}
在这里 void 代表了一个方法没有返回值。
当我们需要创建一个对象的时候我们需要使用 new 操作符:
Person person = new Person();
更加简洁的方式如下:
var person = new Person();
我们使用 new 操作符来动态分配内存空间给一个对象。在 C# 中,你不需要担心释放内存的问题。CLR 中有一个组件叫做GC(Garbage Collector 垃圾回收),它可以自动回收未被使用的对象的内存空间。
一旦我们创建了一个对象,我们就可以通过加点的方式来访问它的字段和方法:
Person person = new Person();
person.Name = "Mosh";
person.Introduce();
2 static 修饰符
当我们对类中的成员使用 static 修饰时,就使得这个成员只能够通过该类获取到,而不能通过任何对象来获取。所以在先前的示例中,如果 Introduce 函数被声明为静态(static)类型,我们就可以通过 Person 类来访问它:
Person.Introduce();
我们使用静态成员是希望该成员在内存中仅有一份实例。比如说,Main 函数在任何一个程序中都被声明为静态的,因为我们希望应用程序的入口只有一个。
在实际运用中,我们最好避免使用静态成员,因为这样做会使得编写自动化测试的工作变得十分困难。自动化测试并非本课程的主题,现在我们只需要记住如何使用已经被定义为静态的成员即可。
3 结构体
结构体是与类相似的一种类型,它将相关的字段和方法组合到一起:
public struct RgbColor
{
public int Red;
public int Green;
public int Blue;
}
我们一般只在轻量化的对象中使用结构体,它能给性能带来一点微小的提升。在实际应用中,99%的情况下,我们都会使用类来创建新的类型而非使用结构体。
在 .NET 中,所有的基本类型都被定义为结构体。它们的体积都很小而且很轻量。最大的基本类型也不超过 16 字节。
4 数组
数组是一种用于存储一些相同类型变量的数据结构。打个比方说,我们可以创建一个整型数组而不是单独声明三个整型变量(前提是他们之间确实有关联):
int[] numbers = new int[3];
在 C# 中,数组实际上是 Array 类的实例。因此我们需要使用 new 操作符来对该对象动态分配内存空间。中括号中的 3 代表了这个数组的长度。一旦数组被创建了,它的长度就不可更改。如果你需要可变长的数组,需要使用 List 类。
想要访问数组中的元素,我们需要使用方括号加下标:
numbers[0] = 1;
在 C# 中,数组的下标从 0 开始。
5 字符串
字符串是一些字符的序列。在 C# 中我们使用双引号将字符串内容括起来,而当个字符则使用单引号。
string name = "Mosh";
char ch = 'A';
想要创建一个字符串,有很多种方法:
- 使用双引号直接创建
string firstName = "Mosh";
- 使用字符串连接生成新字符串
string name = firstName + " " + lastName;
- 使用 string.Format 通过指定格式生成新字符串:
string.Format("{0} {1}", firstName, lastName);
- 使用 string.Join 将数组中的元素连接成新字符串:
var names = new int[3] {1, 2, 3};
string list = string.Join(",", numbers);
在 C# 中,字符串本身是不可修改的,我们使用任何一个 String 类的方法生成出来的新字符串都是一个新的字符串。
5.1 String 和 string
C# 中的任何一种类型都会映射到 .NET 框架中。所以,C# 中的 string 类型会映射到 .NET 中的 String 类型。因此,我们使用下面两种方法声明字符串变量是一样的:
string name;
//String name;
唯一的区别在于,如果想要使用 String 类型,就需要引入命名空间 System,因为 String 类型定义在命名空间 System 中。
using System;
5.2 转义字符
在 C# 中有一些特殊的字符被称为转义字符:
Escape Character | Description |
---|---|
\n | 换行 |
\t | 跳格 |
\ | 反斜杠字符(\)本身 |
' | 单引号 |
" | 双引号 |
如果想要在字符串中表示一个换行,需要使用 \n。
由于反斜杠字符被当做转义字符的前缀使用了,所以如果我们要使用反斜杠本身,我们就需要写两个反斜杠:
string path = "c:\\folder\\file.txt";
5.3 逐字字符串
当一个字符串中的转义字符比较多的时候,代码就会变得十分难读,例如:
var message = "Hi John\nLoock at the following path:\\folder1\\folder2";
我们可以使用逐字字符串重写这部分内容,只需要在字符串前面增加 @ 标记就可以不使用转义字符了:
var message = @"Hi John
Look at the following path:c:\folder1\folder2";
用多了转义字符以后,使用逐字字符串反而不习惯了(笑哭)
6 引用类型和值类型
在 C# 中,我们创建的变量主要有两种类型:类和结构体。
类是引用类型而结构体是值类型。
6.1 值类型
当我们将值类型的变量值传递给另一个变量时,就会传递一份源变量的值的拷贝给目标变量。因此,这两个变量之间是相互独立的:
var i = 10;
var j = i;
j++;
虽然我们增加了 j 的值,但并不会影响到 i。
通俗的说,如果我们将一个值类型的参数传入一个方法,该参数的值会被拷贝。所以在方法内部对该参数进行的任何操作在返回时都会丢失。
C# 的所有基本类型都是结构体,因此它们都是值类型。任何自定义的结构体也都将是值类型。
6.2 引用类型
如果将引用类型变量的值传递给另一个变量,我们只会将该变量的引用传递给另一个变量(即传递了源变量所指向的对象的地址)。也就是说,如果我们在方法内部对任意一个变量进行的修改都会影响到另一外一边:
var arr1 = new int[3] {1, 2, 3};
var arr2 = arr1;
arr2[0] = 0;
代码中 arr1 和 arr2 指向的是内存中的同一个对象。所以在第三行修改 arr2 的第一个元素为 0 时,arr1 的第一个元素也变成了 0。
数组和字符串都是类,所以它们都是引用类型。任何自定义的类都将会是引用类型。
7 枚举
枚举是一组键值对组成的数据结构。当需要定义一组相关的常量时,就可以使用枚举:
public enum ShippingMethod
{
Regular = 1,
Express = 2
}
现在就可以声明一个类型为 ShippingMethod 的变量,然后通过类型名加点的方式进行初始化:
var method = ShippingMethod.Express;
枚举的值在底层实际上是整型值,所以我们可以非常简单的将它变为整型值或者将整型值变为对应的枚举值:
var methodId = 1;
var method = (ShippingMethod)methodId;
//var method = ShippingMethod.Express;
//var methodId = (int)method;
如果要将枚举值转换为字符串,我们可以使用 ToString 方法(参考 Java)。任何一个 C# 的对象都拥有一个 ToString 方法来转换成字符串。
var mehodName = method.ToString();
如果要将一个字符串转变为枚举值,就需要用到 Enum.Parse:
var method = (ShippingMethod)Enum.Parse(typeof(ShippingMethod), methodName);