C#值参数和引用参数
一、值参数
未用ref或out修饰符声明的参数为值参数。
使用值参数,通过将实参的值复制到形参的方式,把数据传递到方法。方法被调用时,系统做如下操作。
- 在栈中为形参分配空间。
- 复制实参到形参。
值参数的实参不一定是变量。它可以是任何能计算成相应数据类型的表达式。
看一个例子:
float func1(float val) //声明方法
{
float j=2.6F;
float k=5.1F;
....
}
下面来调用方法
float fValue1=func1(k); //实参是float类型的变量 float fValue2=func1((k+j)/3); //实参可以计算成float表达式
在把变量作用于实参之前,变量必须赋值(除非是out参数)。对于引用类型,变量可以被设置为一个实际的引用或null。
下面的代码展示了一个名为MyMethod的方法,它有两个参数,一个是MyClass型变量和一个int。
class MyClass
{
public int Val = ;
}
class Program
{ static void MyMethod(MyClass f1, int f2)
{
f1.Val = f1.Val + ;
f2 = f2 + ;
Console.WriteLine("f1.Val: {0}, f2: {1}", f1.Val, f2);
}
static void Main(string[] args)
{
MyClass a1 = new MyClass();
int a2 = ; MyMethod(a1, a2); Console.WriteLine("f1.Val: {0}, f2: {1}", a1.Val, a2);
}
}
我们用图来表示实参和形参在方法执行的不同阶段的值。
- 在方法被调用前,用作实参的a2已经在栈里了。
- 在方法开始前,系统在栈中为形参分配空间,并从实参复制值。
- 因为a1是引用类型,所以引用被复制,结果实参和形参都引用堆中的同一对象。
- 因为a2是值类型,所以值被复制,产生了一个独立的数据项。
- 在方法的结尾,f2和对象f1的字段都被加上了5。
- 方法执行后,形参从栈中弹出。
- a2,值类型,它的值不受方法行为的影响。
- a1,引用类型,但它的值被方法的行为改变了。

二、引用参数
使用引用参数时,必须在方法的申明和调用中都使用关键字ref修饰符。
实参必须是变量,在用作实参前必须被赋值。如果是引用类型的变量,可以赋值为一个引用或者null值。
下面的代码阐明了引用参数的声明和调用的语法:
void MyMethod(ref int val) //方法声明包含ref修饰符
{
//your code
}
int y = ;
MyMethod(ref y); //方法调用 MyMethod(ref +); //错误,形参必须是变量
在第一小节的内容中我们知道,对于值参数,系统在栈上为形参分配内存,相反对于引用参数:
- 不会为形参在栈上分配内存。
- 实际情况是,形参的参数名将作为实参变量的别名,指向相同的内存位置。
由于形参名和实参名的行为,就好象指向相同的内存位置,所以在方法的执行过程中,对形参作的任何改变,在方法完成后依然有效(表现在实参变量上)。
在方法的声明和调用上都使用关键字ref.
下面的代码再次展示了方法MyMethod,但这一次参数是引用参数而不是值参数。
class MyClass
{
public int Val = ;
}
class Program
{ static void MyMethod(ref MyClass f1,ref int f2)
{
f1.Val = f1.Val + ;
f2 = f2 + ;
Console.WriteLine("f1.Val: {0}, f2: {1}", f1.Val, f2);
}
static void Main(string[] args)
{
MyClass a1 = new MyClass();
int a2 = ; MyMethod(ref a1, ref a2); Console.WriteLine("f1.Val: {0}, f2: {1}", a1.Val, a2); }
}
同样,还是用图来阐明方法执行的不同阶段实参和形参的值。
- 在方法被调用前,用作实参的a1,a2已经在栈里了。
- 在方法的开始,形参名被设置为实参的别名。变量a1和f1引用相同的内存位置,a2和f2引用相同的内存位置。
- 在方法的结束位置,f2和对象f1的字段都被加上了5。
- 方法执行之后,形参的名称已经失效,但是值类型a2和引用类型a1所指向的对象的值都被方法内的行为改变了。

三、引用类型作为值参数和引用参数
对于一个引用类型对象,不管是将其作为值参数传递还是作为引用参数传递,我们都可以在方法成员内部修改它的成员。不过,我们并没有在方法内部设置形参本身。
下面我们就来看看在方法内部设置形参本身时会发生什么。
1、将引用类型对象作为值参数传递
class MyClass
{
public int Val = ;
}
class Program
{ static void RefAsParameter(MyClass f1)
{
f1.Val = ;
Console.WriteLine("After member assignment: {0}", f1.Val);
f1 = new MyClass();
Console.WriteLine("After new object creation: {0}", f1.Val);
}
static void Main(string[] args)
{ MyClass a1 = new MyClass();
Console.WriteLine("Before method call: {0}", a1.Val);
RefAsParameter(a1);
Console.WriteLine("After method call: {0}", a1.Val);
}
}
这段代码的输出如下:
Before method call:
After member assignment:
After new object creation:
After method call:
同样,还是用图来阐明以下几点。
- 在方法开始时,实参和形参都指向堆中相同的对象。
- 在为对象的成员赋值之后,他们仍指向堆中相同的对象。
- 当方法分配新的对象并赋值给形参时,方法外部的实参仍指向原始对象,而形参指向的是新对象。
- 在方法调用之后,实参指向原始对象,形参和新对象都会消失。

2、将引用类型对象作为引用参数传递
除了在方法声明和方法调用时使用ref关键字之外,与上面的代码完全一样。
class MyClass
{
public int Val = ;
}
class Program
{ static void RefAsParameter(ref MyClass f1)
{
f1.Val = ;
Console.WriteLine("After member assignment: {0}", f1.Val);
f1 = new MyClass();
Console.WriteLine("After new object creation: {0}", f1.Val);
}
static void Main(string[] args)
{ MyClass a1 = new MyClass();
Console.WriteLine("Before method call: {0}", a1.Val);
RefAsParameter(ref a1);
Console.WriteLine("After method call: {0}", a1.Val);
}
}
这段代码的输出如下:
Before method call:
After member assignment:
After new object creation:
After method call:
我们开始说过,引用参数的行为就是将实参作为形参的别名。
- 在方法开始时,实参和形参都指向堆中相同的对象。
- 在为对象的成员赋值之后,他们仍指向堆中相同的对象。
- 当方法分配新的对象并赋值给形参时,形参和实参都指向新对象。
- 在方法调用之后,实参指向方法内创建的新对象

四、写在最后
这些都是老生常谈的问题,为什么还要写?
一是因为今天看书看到了与此相关的内容,回去翻了翻书,然后记录下来
二是供自己以后查阅,毕竟看博客比翻书来的快。
最后,祝大家周末愉快,玩的开心。
C#值参数和引用参数的更多相关文章
- C#方法的六种参数,值参数、引用参数、输出参数、参数数组、命名参数、可选参数
方法的参数有六种,分别是值参数.引用参数.输出参数.参数数组.命名参数.可选参数. 值参数 值参数是方法的默认类型,通过复制实参的值到形参的方式把数据传递到方法,方法被调用时,系统作两步操作: 在栈中 ...
- C#_delegate - 值参数和引用参数
值参数不能加,引用参数可以. 引用参数是共享的 using System; using System.Collections.Generic; using System.Linq; using Sys ...
- C#的值参数与引用参数
值参数:在使用值参数时,是把变量的值传给函数,函数中对此变量的任何修改都不影响该变量本身的值. 引用参数:使用引用参数时,在函数中对此变量的修改会影响变量的值. 说简单点,值参数,就是我把身份证复印件 ...
- c#中引用类型作为值参数和引用参数问题
一.分类 C#的值类型包括:结构体(数值类型,bool型,用户定义的结构体),枚举,可空类型. C#的引用类型包括:数组,用户定义的类.接口.委托,object,字符串. 二.参数传递 对于引用类型, ...
- 传入值参数&传入引用参数的区别
传值&传引用 1.传值 是把实参的值赋值给行参 那么对行参的修改,不会影响实参的值 2.传地址 是传值的一种特殊方式,只是他传递的是地址 那么传地址以后,实参和行参都指向同一个对象 3.传引用 ...
- [C++学习历程]基础部分 C++中的函数中的值参数、地址参数、引用参数实际例子
本文地址:http://blog.csdn.net/sushengmiyan/article/details/20406269 作者:sushengmiyan // sushengmiyanTest. ...
- python-在定义函数时,不定长参数中,默认值参数不能放在必选参数前面
如果一个函数的参数中含有默认参数,则这个默认参数后的所有参数都必须是默认参数,否则会报错:SyntaxError: non-default argument follows default argum ...
- python中函数的参数:必传参数(位置参数)、默认值参数、参数组传参、关键字传参
1.必传参数也叫做位置参数,因为必填,也必须对应位置 2.默认值参数如上图的word 3.参数组参数:传进去的是0个.或多个value的形式,,,和位置参数有点像,只传value值,但是没有限制个数 ...
- C#方法参数--值参数,引用参数,输出参数
值参数: 使用值参数,通过复制实参的值到形参的方式,把数据传递到方法,方法被调用的时候,系统做如下操作: 在栈中为形参分配空间: 复制实参到形参. 注意:一个值参数的实参不一定是变量,它可以是任何能够 ...
随机推荐
- 使用siege对web接口进行post方式的压力测试
为了达到压力测试的效果,需要申请一台线上机器,并且安装压力测试的工具siege. 安装新版siege.资料说yum安装的版本2.70对于post方式支持的不好,验证后发现请求可以正常发过去,但是打开d ...
- Linux软件安装管理
1.软件包管理简介 1.软件包分类 源码包 脚本安装包 二进制包(RPM包.系统默认包) 2.源码包 源码包的优点是: 开源,如果有足够的能力,可以修改源代码 可以自由选择所需要的功能 软件设计编译安 ...
- Django Cookie 和 Sessions 应用
在Django里面,使用Cookie和Session看起来好像是一样的,使用的方式都是request.COOKIES[XXX]和request.session[XXX],其中XXX是您想要取得的东西的 ...
- win10 uwp 装机必备应用 含源代码
zhxilin大神说http://www.cnblogs.com/zhxilin/p/4819372.html这文章说到了使用await Windows.System.Launcher.LaunchU ...
- PHP 页面静态化/纯静态化/伪静态化
个人博客迁移至独立博客:https://blog.plcent.com/,欢迎大家访问 概念 PHP静态化分为:纯静态化 和 伪静态化:纯静态化又分为:局部静态化 和 完全静态化 纯静态化:是把PHP ...
- 如何升级laravel5.4到laravel5.5并使用新特性?
如何升级laravel5.4到laravel5.5并使用新特性? 修改composer.json: "laravel/framework": "5.5.*", ...
- 在unity3d游戏中添加中文语音控制
最近打算尝试一下OLAMI在游戏中应用的可能性,这里做一下记录. unity官方教程中的几个项目很精简,但看起来很不错,里面有全套的资源.最后我选择了tanks-tutorial来做这个实验. 下载和 ...
- Appium python自动化测试系列之滑动函数封装实战(八)
8.1 什么是函数的封装 教科书上函数的封装太官方,我们这里暂且将函数的封装就是为了偷懒把一些有共性的功能或者一些经常用的功能以及模块放在一起,方便我们以后再其他地方调用.这个只是个人的理解所以大家懂 ...
- 超文本传送协议HTTP
1. HTTP的操作过程: HTTP是面向事务的应用层协议.HTTP协议本身是无连接的,为了保证数据的可靠传输,HTTP使用了面向连接的TCP作为运输层协议.所以,在发送HTTP报文之前都需要先建立T ...
- LeetCode 548. Split Array with Equal Sum (分割数组使得子数组的和都相同)$
Given an array with n integers, you need to find if there are triplets (i, j, k) which satisfies fol ...