C# 形参 实参 调用时在托管栈和托管堆中的分配情况
每每看到别人写的文章,总觉得冗长,不够简练,作为1个开发我们要力求简洁明了,当然人非圣贤孰能无过,我写的也不是尽善尽美,我尽我所能保证每一句随笔的正确性,期间我会参考很多来源的资料,当然也会在文章最后列出原博客地址,如果你觉得我写的不够清楚,那么你可以参考这些地址做详细阅读。
作者本身也是很愿意和大家一起交流技术,如果你看了我的文章中间有不同的论断和见解,那么你可以在下方留言,作者看到留言都会回复,一起探讨.NET技术。
以下内容来源于网络加自己的认同的理解,和自己认为一些重要的东西。
CLR数据类型: 值类型(Value Type)和引用类型(Reference Type)
值类型:int、char、float、long、bool、double、struct、enum、short、byte、decimal、sbyte、uint、ulong、ushort等
引用类型:string、class、interface、delegate、object等
对于如下代码:
int myAge = 19;
Student myStu = new Student("唐马儒", 20);
public void test(int age, Student stu);
test(myAge, myStu);
函数定义了形参,当真正调用函数的时候,传递的参数就是实参。
对于基本值类型,默认情况下是传递值的拷贝,在栈中会开辟一块内存,拷贝myAge的值到为栈中名称为age的地址中去,对于Student类的实例,内存只需要在栈中创建了1个指针。放在名称为stu的地址空间中,指向heap中的学生对象,栈中名称为myStu内的Pointer也指向heap中的学生对象。
思考:1. 如果形参和实参的名称相同,那么在栈中重新开辟内存空间的时候,新空间的名称叫什么?
但是C#提供了ref和out修饰符来修饰函数参数,如果遇到了这2种情况(ref一般是加在值类型前面,因为加在引用类型前面没有意义),调用函数就不会再栈中重新开辟一块内存来存放age这个值,而是把myAge的地址传递给调用内部,这样在调用内部对变量的修改就会反映到外部代码,这个过程中没有装箱(boxing)和拆箱(unboxing)。
附加1个知识点:
1. C#对于引用类型实例对象的值类型成员与对象一起存放在heap中
2. 对于值类型(比如结构体)中的引用类型的创建的对象是保存在heap中,stack中仅保留这个对象成员的引用(也叫指针 Pointer)
C#有1条黄金规则:
1. 所有引用类型都是放在heap中
2. 值类型和指针总是放在它们被声明的地方
参考资料:
2. C#中的ref, out, params修饰符+引用类型和值类型说明
6. IL代码怎么看懂