简单复习一下 C# 基础语法(第四期)。
值类型和引用类型
值类型,直接存储数据。
引用类型,存储内存地址,通过地址找到数据。
值类型:int,float,double,bool,char 等等。
引用类型:string,class 等等。
值类型赋值时,会创建值的副本。
修改值类型变量,不会影响其他值类型变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Program { static void Main() { int x = 1; int y = x; x = 0; Console.WriteLine("x = " + x); Console.WriteLine("y = " + y); } }
|
引用类型,两个变量引用的对象相同时,对其中一个变量引用的对象进行修改,另一个变量引用的对象也发生了变化。
因为这两个变量只是存储了一个地址,指向同一块数据区域。
就好比,两个人使用同一个银行账户,一个人取走了全部的钱,另一个人就没钱了。
例如,有一个账户类,包含余额字段,存钱、取钱、查询余额的方法。
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
| public class Account { private float money;
public void Save(float money) { if (money > 0) { this.money += money; Console.WriteLine("存入 " + money); } }
public void Draw(float money) { if (money > 0) { if (this.money >= money) { this.money -= money; Console.WriteLine("取出 " + money); } else { Console.WriteLine("余额不足"); } } }
public void Query() { Console.WriteLine("余额 " + money); } }
|
现在创建一个账户对象,赋值给 myAccount,接着再赋值给 herAccount,两个 Account 变量引用的是同一个对象。
在我的账户存入 10 元,从她的账户取出 10 元,我的账户余额 0 元。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Program { static void Main() { Account myAccount = new Account(); Account herAccount = myAccount;
myAccount.Save(10f); herAccount.Draw(10f); myAccount.Query(); } }
|
装箱和拆箱
装箱,把值类型转换成引用类型。
拆箱,把引用类型转换成值类型。
1 2 3 4 5 6 7 8 9 10 11
| public class Program { static void Main() { int i = 1; object obj = i; int j = (int)obj; } }
|
有时候为了通用,会把方法的参数类型定义为 object,当传入一个值类型参数时,就会需要装箱。
由于装箱会生成新的对象,对运行效率有一定影响,一般是尽量避免装箱和拆箱的。
装箱和拆箱时,对两个变量的值进行修改,是互不影响的。
ref 和 out
通常,当方法的参数是值类型时,外部传入的变量和方法体内的参数变量,是分别独立的,对方法体内的参数变量修改时,不会影响到外部的变量。
这是因为方法内的形参,只是外部传入的实参的一个副本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Program { static void Main() { int i = 0; Add(i); Console.WriteLine("i = " + i); }
static void Add(int i) { i++; } }
|
如果要实现当 i 传入 Add 方法内,执行之后 i 的数值增加,则需要使用 ref 关键字。
方法的参数类型前面要加个 ref,调用方法时,传入的参数前面也要加个 ref。
此时,i 变成了按引用传参,在方法内对 i 进行修改,同时也会影响到外部的 i。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Program { static void Main() { int i = 0; Add(ref i); Console.WriteLine("i = " + i); }
static void Add(ref int i) { i++; } }
|
需要注意的是,外部的 i 需要赋初始值,如果没有赋值,则会报错。
ref 的特点是有进有出,需要先赋值,再传入,有输出。
out 也是按引用传参,不过 out 只是用来输出多个参数。
out 的特点是只出不进,不需要先赋值,方法会把内部的数值输出到外部的变量,即使赋初始值,也会被输出的数值覆盖。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Program { static void Main() { int i; int j = 3; Add(out i, out j); Console.WriteLine("i = " + i); Console.WriteLine("j = " + j); }
static void Add(out int i, out int j) { i = 1; j = 2; } }
|