值类型与引用类型
简单来说就是将值类型变量或引用类型变量作为参数传入方法操作后原值的变化
简单回顾,之前细说过值类型与引用类型的区别在内存中的变化,因此不再赘述
1)内存中的区别:值类型主要存储在栈中;引用类型存储在中栈,堆中(主要是堆)
2)继承中的区别:值类型继承自System.ValueType(System.ValueType又继承自System.Object) 引用类型继承自System.Object;因此C#中Object类可以称之为”祖宗类”
值类型主要有:byte,int,short,float,double,long,decimal,char,bool,struct,enum等
引用类型主要有:object,string,Array,class,interface等

值类型与引用类型各自的继承关系
值类型变量赋值会拷贝一个副本 引用类型变量的赋值只复制对对象的引用
static void Main(string[] args)
{
//值类型
int n = 6;
int m = n;
m = m + 2;
Console.WriteLine("n = {0} m = {1}", n, m);
Console.WriteLine("");
//修改m的值不会影响n的值
//验证:拷贝一个副本
//引用类型
int[] ns1 = new int[1] { 1 };
Console.WriteLine("ns1[0] = {0}", ns1[0]);
int[] ns2 = ns1;
Console.WriteLine("ns2[0] = {0}",ns2[0]);
ns1[0] = 3;
Console.WriteLine("ns1[0] = {0}",ns1[0]);
//修改ns2[0]的值会影响ns1[0]的值
//验证:复制对对象的引用
//看不懂的单击上面连接或查找039文章
//详细说明了内存中变量指针的指向,不再赘述
Console.ReadKey();
}
值传递
将值类型变量或数据传入方法操作后查看原值(主要是理解值类型传递副本)

值传递
static void Main(string[] args)
{
int n = 6;
M1(n);//在方法内部 X=9
//方法未返回x操作后的值
//因此n 还是原值 6
Console.WriteLine(n);//6
Console.WriteLine("");
//在方法内部操作后返回
//最关键的是n又接收了操作后的值
//因此 n =9
n = M2(n);
Console.WriteLine(n);//9
//如果 m 没有进行接收
int m = 6;
M2(m);
//M2()虽然有返回值,但是没有接收
//因此 M2()中 y =9
//m 还是原值 6
Console.WriteLine(m);//6
//m 没有接收M2()的返回值
//无论在方法内对m做任何操作,外部的m值不变
Console.ReadKey();
}
//静态方法
static void M1(int x)
{
//无论怎么加减乘除,都不影响外部 n 的值
x += 3;
}
static int M2(int y)
{
//操作后返回
//如果外部没有接收 m还是原值
//如果外部 m 接收了方法的返回值
//m 就是9 相当于 6+3
return y += 3;
}
引用传递
将引用类型的变量或数据传入方法(主要是理解引用类型传递的是对象的地址)
static void Main(string[] args)
{
Person p1 = new Person();
p1.Name = "张三";
p1.Age = 18;
M3(p1);//结果 李四 180
Console.WriteLine(p1.Name + " " + p1.Age);
Console.ReadKey();
}
static void M3(Person p3)
{
p3.Name = "李四";
p3.Age = 180;
}

把p1对象在栈中的地址赋给p3(p3 类似是 p1 的快捷方式)
static void Main(string[] args)
{
Person p1 = new Person();
p1.Name = "张三";
p1.Age = 18;
M3(p1);//结果 李四 180
Console.WriteLine(p1.Name + " " + p1.Age);
Console.ReadKey();
}
static void M3(Person p3)
{
p3.Name = "李四";
p3.Age = 180;
}

将p2对象的堆地址赋给p5即p5对象也指向p2对象
static void Main(string[] args)
{
Person p3 = new Person();
p3.Name = "王五";
p3.Age = 19;
M6(p3);//王五 19
Console.WriteLine(p3.Name + " " + p3.Age);
Console.ReadKey();
}
static void M6(Person px)
{
Person p6 = new Person();
px = p6;
px.Name = "张三三";
px.Age = 190;
}

px指向p6对象 因此修改的不再是 p3的属性值
px与p6指向堆地址 0x002,最后只有p3指向堆地址 0x001
//对照前三个示例,自己理清 M7()方法的结果
static void Main(string[] args)
{
Person p4 = new Person();
p4.Name = "王五";
p4.Age = 19;
M7(p4);//张三 20
Console.WriteLine(p4.Name + " " + p4.Age);
Console.ReadKey();
}
static void M7(Person p4x)
{
p4x.Name = "张三";
p4x.Age = 20;
Person p7 = new Person();
p4x = p7;
p4x.Name = "王五";
p4x.Age = 190;
}
使用ref/out进行传值
ref和out都是按地址传递,使用后都将改变原参数的值(值类型,传递的是栈本身的地址;引用类型,传递的是引用地址所在栈的地址)
out修饰的参数在方法外部既可以赋值也可以不赋值;在方法该参数必须赋值
ref修饰的参数与其正好相反
//对照前三个示例,自己理清 M7()方法的结果
static void Main(string[] args)
{
//使用ref传值
//传入值类型
int n = 6;
M8(ref n);//9
Console.WriteLine(n);
Console.WriteLine("");
//传入引用类型
int[] ns = new int[] { 1 };
M9(ref ns);//8
Console.WriteLine(ns[0]);
//=========================
//使用out进行传值
//传入值类型
int m = 8;
M10(out m);//2
Console.WriteLine(m);
Console.WriteLine("");
//传入引用类型
int[] ms = new int[1];
ms[0] = 1;
M11(out ms);//5
Console.WriteLine(ms[0]);
Console.ReadKey();
}
static void M8(ref int nx)
{
nx = nx + 3;
}
static void M9(ref int[] nsx)
{
nsx = new int[] { 8 };
}
static void M10(out int m)
{
m = 2;
}
static void M11(out int[] msx)
{
msx = new int[1] { 5 };
}

使用ref/out 传递值类型或引用类型
© 版权声明
文章版权归作者所有,未经允许请勿转载。如内容涉嫌侵权,请在本页底部进入<联系我们>进行举报投诉!
THE END















- 最新
- 最热
只看作者