记得在刚开始学习c#的时候,就会接触到值类型和引用类型,当时对这两者之间的区别不是特别清楚。现在互联网上关于这两者之间的区别的文章很多,一般说下来有以下几点。
1. 值类型主要是由结构和枚举类型组成,这里面的结构还包括整型,浮点型等系统预定义类型和用户自定义的结构类型。值类型的变量直接包含实例值,其值是直接存储在内存的堆栈上的,故使用值类型的效率会比较高 。引用类型的变量保存的实例在内存中地址,其将实例的地址存储在内存的堆栈上。因此基于这点区别,在复制值类型的变量时,直接是将变量完全拷贝,拷贝结束之后,两个变量之间即没有了任何关系。而引用类型则只是复制了实例的地址,两个变量所对应的实例的地址还是一样的,当实例的值发生变化时,这两个变量所表示的值也相应的发生变化。
2. 值类型是不能派生的,故不能被继承。
3. 值类型不能赋值为null,但是如果该值类型被定义为可空类型时,则可以为null
下面的代码简要描述一下:
1
private
void
TestRef()
2 {
3 int num1 = 1;
4 int num2 = num1;
5 string str1 = "a";
6 string str2 = str1;
7 Console.Write(" num1:{0}/n num2:{1}/n str1:{2}/n str2:{3}/n",num1,num2,str1,str2);
8
9 num1 = 2;
10 str1 = "b";
11 Console.Write("===========================================/n");
12 Console.Write(" num1:{0}/n num2:{1}/n str1:{2}/n str2:{3}/n", num1, num2, str1, str2);
13 }
2 {
3 int num1 = 1;
4 int num2 = num1;
5 string str1 = "a";
6 string str2 = str1;
7 Console.Write(" num1:{0}/n num2:{1}/n str1:{2}/n str2:{3}/n",num1,num2,str1,str2);
8
9 num1 = 2;
10 str1 = "b";
11 Console.Write("===========================================/n");
12 Console.Write(" num1:{0}/n num2:{1}/n str1:{2}/n str2:{3}/n", num1, num2, str1, str2);
13 }
输出结果:
num1:1 num2:1 str1:a str2:a
======================
num1:2 num2:1 str1:b str2:b
接下来可以看一下关于ref,out以及普通的传参之间的区别:
先看下代码:
1using System;
2using System.Collections.Generic;
3using System.Text;
4
5namespace Practice
6{
7 public class Cs_Ref
8 {
9
10 public void GetValue(string str, int num)
11 {
12 str = "test";
13 num = 11;
14 }
15
16 public void GetValue(ref string str, ref int num)
17 {
18 str = "test";
19 num=11;
20 }
21
22 public void GetValue(out int num, out string str)
23 {
24 str = "test";
25 num = 11;
26 }
27
28 }
29}
2using System.Collections.Generic;
3using System.Text;
4
5namespace Practice
6{
7 public class Cs_Ref
8 {
9
10 public void GetValue(string str, int num)
11 {
12 str = "test";
13 num = 11;
14 }
15
16 public void GetValue(ref string str, ref int num)
17 {
18 str = "test";
19 num=11;
20 }
21
22 public void GetValue(out int num, out string str)
23 {
24 str = "test";
25 num = 11;
26 }
27
28 }
29}
1 private void TestRef()
2 {
3 int num1 = 1;
4 int num2 ;
5 string str1 = "a";
6 string str2;
7
8 Cs_Ref cs = new Cs_Ref();
9 Console.Write("==============================/n");
10 cs.GetValue(str1,num1);
11 Console.Write("num1:{0}/n str1:{1}/n",num1,str1);
12
13 cs.GetValue(ref str1, ref num1);
14 Console.Write("==============================/n");
15 Console.Write("num1:{0}/n str1:{1}/n", num1, str1);
16
17 cs.GetValue(out num2, out str2);
18 Console.Write("==============================/n");
19 Console.Write("num2:{0}/n str2:{1}/n", num2, str2);
20
21 Console.ReadLine();
22 }
2 {
3 int num1 = 1;
4 int num2 ;
5 string str1 = "a";
6 string str2;
7
8 Cs_Ref cs = new Cs_Ref();
9 Console.Write("==============================/n");
10 cs.GetValue(str1,num1);
11 Console.Write("num1:{0}/n str1:{1}/n",num1,str1);
12
13 cs.GetValue(ref str1, ref num1);
14 Console.Write("==============================/n");
15 Console.Write("num1:{0}/n str1:{1}/n", num1, str1);
16
17 cs.GetValue(out num2, out str2);
18 Console.Write("==============================/n");
19 Console.Write("num2:{0}/n str2:{1}/n", num2, str2);
20
21 Console.ReadLine();
22 }
输出结果:
num1:1 str1 :a
===================
num1:11 str1:test
===================
num2:11 str2: test
故由上代码执行可知,在一般的传参的时候,并不改变实参之前的值,类似于拷贝值类型的特点,即实参的值不会因为所执行的方法而进行改变
而通过ref关键字之后可以看见,实参的值会因为所执行的方法而改变
out关键字则是在执行方法之前,实参可以不必赋值。