C#值参数和引用参数

2023-11-12

C#值参数和引用参数

一、值参数

未用ref或out修饰符声明的参数为值参数。

使用值参数,通过将实参的值复制到形参的方式,把数据传递到方法。方法被调用时,系统做如下操作。

  • 在栈中为形参分配空间。
  • 复制实参到形参。

值参数的实参不一定是变量。它可以是任何能计算成相应数据类型的表达式。

看一个例子:

1

2

3

4

5

6

float func1(float val)    //声明方法

{

  float j=2.6F;

  float k=5.1F;

  ....

}

下面来调用方法

1

2

3

float fValue1=func1(k);        //实参是float类型的变量

 

float fValue2=func1((k+j)/3);  //实参可以计算成float表达式

在把变量作用于实参之前,变量必须赋值(除非是out参数)。对于引用类型,变量可以被设置为一个实际的引用或null。

下面的代码展示了一个名为MyMethod的方法,它有两个参数,一个是MyClass型变量和一个int。

复制代码

 1  class MyClass
 2     {
 3         public int Val = 20;
 4     }
 5     class Program
 6     {
 7 
 8         static void MyMethod(MyClass f1, int f2)
 9         {
10             f1.Val = f1.Val + 5;
11             f2 = f2 + 5;
12             Console.WriteLine("f1.Val: {0}, f2: {1}", f1.Val, f2);
13         }
14         static void Main(string[] args)
15         {
16             MyClass a1 = new MyClass();
17             int a2 = 10;
18 
19             MyMethod(a1, a2);
20 
21             Console.WriteLine("f1.Val: {0}, f2: {1}", a1.Val, a2);
22          }
23     }

复制代码

我们用图来表示实参和形参在方法执行的不同阶段的值。

  • 在方法被调用前,用作实参的a2已经在栈里了。
  • 在方法开始前,系统在栈中为形参分配空间,并从实参复制值。 
  • 因为a1是引用类型,所以引用被复制,结果实参和形参都引用堆中的同一对象。
  • 因为a2是值类型,所以值被复制,产生了一个独立的数据项。
  • 在方法的结尾,f2和对象f1的字段都被加上了5。
  • 方法执行后,形参从栈中弹出。
  • a2,值类型,它的值不受方法行为的影响。
  • a1,引用类型,但它的值被方法的行为改变了。

 

二、引用参数

使用引用参数时,必须在方法的申明和调用中都使用关键字ref修饰符。

实参必须是变量,在用作实参前必须被赋值。如果是引用类型的变量,可以赋值为一个引用或者null值。

下面的代码阐明了引用参数的声明和调用的语法:

  void MyMethod(ref int val)  //方法声明包含ref修饰符
  {
     //your code
   }

 

  int y = 1;
  MyMethod(ref y);   //方法调用

  MyMethod(ref 3+5);  //错误,形参必须是变量

在第一小节的内容中我们知道,对于值参数,系统在栈上为形参分配内存,相反对于引用参数:

  • 不会为形参在栈上分配内存。
  • 实际情况是,形参的参数名将作为实参变量的别名,指向相同的内存位置

由于形参名和实参名的行为,就好象指向相同的内存位置,所以在方法的执行过程中,对形参作的任何改变,在方法完成后依然有效(表现在实参变量上)。

在方法的声明和调用上都使用关键字ref.

下面的代码再次展示了方法MyMethod,但这一次参数是引用参数而不是值参数。

复制代码

 1  class MyClass
 2     {
 3         public int Val = 20;
 4     }
 5     class Program
 6     {
 7 
 8         static void MyMethod(ref  MyClass f1,ref int f2)
 9         {
10             f1.Val = f1.Val + 5;
11             f2 = f2 + 5;
12             Console.WriteLine("f1.Val: {0}, f2: {1}", f1.Val, f2);
13         }
14         static void Main(string[] args)
15         {
16             MyClass a1 = new MyClass();
17             int a2 = 10;
18 
19             MyMethod(ref a1, ref a2);
20 
21             Console.WriteLine("f1.Val: {0}, f2: {1}", a1.Val, a2);
22 
23         }
24     }

复制代码

同样,还是用图来阐明方法执行的不同阶段实参和形参的值。

  • 在方法被调用前,用作实参的a1,a2已经在栈里了。
  • 在方法的开始,形参名被设置为实参的别名。变量a1和f1引用相同的内存位置,a2和f2引用相同的内存位置。
  • 在方法的结束位置,f2和对象f1的字段都被加上了5。
  • 方法执行之后,形参的名称已经失效,但是值类型a2和引用类型a1所指向的对象的值都被方法内的行为改变了。

三、引用类型作为值参数和引用参数

 对于一个引用类型对象,不管是将其作为值参数传递还是作为引用参数传递,我们都可以在方法成员内部修改它的成员。不过,我们并没有在方法内部设置形参本身。

 下面我们就来看看在方法内部设置形参本身时会发生什么。

1、将引用类型对象作为值参数传递

复制代码

 1  class MyClass
 2     {
 3         public int Val = 20;
 4     }
 5     class Program
 6     {
 7 
 8         static void RefAsParameter(MyClass f1)
 9         {
10             f1.Val = 50;
11             Console.WriteLine("After member assignment:   {0}", f1.Val);
12             f1 = new MyClass();
13             Console.WriteLine("After new object creation: {0}", f1.Val);
14         }
15         static void Main(string[] args)
16         {
17 
18             MyClass a1 = new MyClass();
19             Console.WriteLine("Before method  call:       {0}", a1.Val);
20             RefAsParameter(a1);
21             Console.WriteLine("After method  call:        {0}", a1.Val);
22         }
23     }

复制代码

这段代码的输出如下:

Before method  call:       20
After member assignment:   50
After new object creation: 20
After method  call:        50

同样,还是用图来阐明以下几点。

  • 在方法开始时,实参和形参都指向堆中相同的对象。
  • 在为对象的成员赋值之后,他们仍指向堆中相同的对象。
  • 当方法分配新的对象并赋值给形参时,方法外部的实参仍指向原始对象,而形参指向的是新对象。
  • 在方法调用之后,实参指向原始对象,形参和新对象都会消失。

2、将引用类型对象作为引用参数传递

除了在方法声明和方法调用时使用ref关键字之外,与上面的代码完全一样。

复制代码

 1   class MyClass
 2     {
 3         public int Val = 20;
 4     }
 5     class Program
 6     {
 7 
 8         static void RefAsParameter(ref MyClass f1)
 9         {
10             f1.Val = 50;
11             Console.WriteLine("After member assignment:   {0}", f1.Val);
12             f1 = new MyClass();
13             Console.WriteLine("After new object creation: {0}", f1.Val);
14         }
15         static void Main(string[] args)
16         {
17 
18             MyClass a1 = new MyClass();
19             Console.WriteLine("Before method  call:       {0}", a1.Val);
20             RefAsParameter(ref a1);
21             Console.WriteLine("After method  call:        {0}", a1.Val);
22         }
23     }

复制代码

这段代码的输出如下:

Before method  call:       20
After member assignment:   50
After new object creation: 20
After method  call:        20

我们开始说过,引用参数的行为就是将实参作为形参的别名。

  • 在方法开始时,实参和形参都指向堆中相同的对象。
  • 在为对象的成员赋值之后,他们仍指向堆中相同的对象。
  • 当方法分配新的对象并赋值给形参时,形参和实参都指向新对象。
  • 在方法调用之后,实参指向方法内创建的新对象

四、写在最后

程序写着写着,大家都想着做架构师,却往往基础的东西会有忘却

写在此,已做备忘

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C#值参数和引用参数 的相关文章

  • [网络安全自学篇] 八十四.《Windows黑客编程技术详解》之VS环境配置、基础知识及DLL延迟加载详解(1)

    从这篇文章开始 作者将带着大家来学习 Windows黑客编程技术详解 其作者是甘迪文老师 推荐大家购买来学习 作者将采用实际编程和图文结合的方式进行分享 并且会进一步补充知识点 希望对您有所帮助 第一篇文章主要包括两部分内容 开发环境 VS
  • 如何搭建测试环境

    记第一次搭建测试环境的经历 准备工作 环境部署文档 开发提供 xftp 上传 下载文件到Linux xshell 远程连接Linux用 查看哪些端口被打开 netstat an 查看某端口是否被打开 netstat an grep 3306
  • 减轻剪辑工作必备——Python实现让视频自动打码,再也不怕出现少儿不宜的画面了

    我们在观看视频的时候 有时候会出现一些奇怪的马赛克 影响我们的观影体验 那么这些马赛克是如何精确的加上去的呢 有什么python相关报错解答自己不会的 或者源码资料 模块安装 女装大佬精通技巧 都可以来这里 https jq qq com
  • [Office] 公务员WPS Excel常用的一些技巧方法

    这篇文章主要是我最近工作使用WPS Excel的一些常用技巧和方法 仅仅是一篇在线笔记 当然实际操作中 你遇到问题百度经验或相关网站会提供对应的解决方法 而且它们写得更好 这篇文章更多的是结合自己使用学到的技巧 作为程序员 写了这么多年的代
  • 聚簇索引与主键的选择

    聚簇索引与主键的选择 一 什么是聚簇索引 二 什么是非聚簇索引 1 InnoDB引擎中 2 MyISAM引擎中 三 聚簇索引的优劣与主键选择的关系 一 什么是聚簇索引 首先 聚簇索引不是一种单独的索引类型 其实是数据的存储方式 聚簇索引将数
  • 基于Python搭建Django后台管理系统

    一个好的项目数据库管理后台是必须的 今天教大家搭建Django网站后台 好了 开始进入正题 今天以搭建一个个人博客网站作为例子讲解网站后台的搭建 一 博客网站的创建 创建项目 生成站点 sites Model 这两步骤第一篇有介绍 这里就直
  • 浅谈java中的锁

    JAVA中的锁 自旋锁 当一个线程要获取锁的时候 该锁被其他线程获取 那么该线程将循环等待 不判断该锁是否能够被成功获取 直到获取到该锁才会退出循环 自旋锁实现例子 通过CAS操作实现加锁与解锁逻辑 循环等待占用锁的线程解锁 自旋锁代码实现
  • 显著性检验【t-test、方差分析、ks检验】

    显著性检验 t test 方差分析 ks检验 0 目录 1显著性检验基本定义 what 2 使用显著性检验的意义 why 3 显著性检验的具体操作流程 how 1 显著性检验基本定义 统计假设检验 Statistical hypothesi
  • 真的!千万不要忽略这些python常见报错信息

    在使用Python时 作为萌新的我总是会粗心的掉这掉那 运行时就会出现各式各样的错误 因此写这么一篇博客 来总结下编写代码的一些常见错误以及解决办法 有什么python相关报错解答自己不会的 或者源码资料 模块安装 女装大佬精通技巧 都可以
  • 【FPGA基础篇】底层结构组成

    文章目录 前言 CPU和DSP FPGA ASIC对比 FPGA和CPLD比较 FPGA基础 IOB 输入输出单元 CLB 可编程逻辑模块 LUT 查找表 MUX 选择器 复用器 Carry Chain 进位链 Flip Flop 触发器
  • 请求转发和重定向区别

    一 转发和重定向区别详解 作为一名程序员 特别是java web开发的程序员 在使用servlet jsp的时候 我们必须要知道实现页面跳转的两种方式的区别和联系 即转发和重定向的区别 RequestDispatcher forward方法
  • 十六进制的转换为十进制两种常见方法

    十六进制的转换为十进制两种常见方法 好久以前学的都忘了 正好复习一下 对于十六进制转十进制 第一种 快速法 自己挺喜欢第一种的快捷 比如 012A 0 X 163 1 X 162 2 X 161 10 X 160 298 说明 当中的十六进
  • 比较对象相等性的四种方法

    比较对象相等性的四种方法 System Object定义了3个不同的方法 来比较对象的相等性 ReferenceEquals 和两个版本的Equals 再加上比较运算符 实际上是有四种比较相等的方式 在编程中实际上我们只需要这两种比较 c
  • Bundle Adjustment 光束平差法

    https www cnblogs com Jessica jie p 7739775 html 感觉这个链接讲的比较好理解 看slam的书完全一脸懵
  • C#知识结构

    对于一个工作多年的程序员而言 接口 反射 索引器 事件 委托这些耳熟能详的词汇 提起来别说多简单了 但是让老司机坐在那一个人拿起一支笔 把脑海中对C 知识结构进行梳理一下 大抵是写不了多内容的 原因是什么呢 是遗忘 当然不是 每天面对代码的
  • 区块链技术基本概念

    链客 专为开发者而生 有问必答 此文章来自链客区块链技术问答社区 未经允许拒绝转载 区块链技术根本概念 了解这些名词是一个不错的开端 公钥加密系统 Alice有一把公钥和一把私钥 她可以用她的私钥创建数字签名 而Bob可以用她的公钥来验证这
  • JSON Schema 详解

    简介 要真正理解 JSON Schema 首先需要知道什么是 JSON JSON 代表 JavaScript对象表示法 是一种简单的数据交换格式 它最初是万维网的一个符号 因为JavaScript存在于大多数Web浏览器中 而JSON是基于
  • 在HTML中怎么去掉超链接(标签 a)的下划线?

    转自 http zhidao baidu com question 253614370 html qbl relate question 0 word a 20 C8 A5 CF C2 BB AE CF DF a href 超链接 a
  • Byte位元组单位-KB KiB MB MiB GB GiB区别

    一般而言大部份都只知道KB MB GB TB 等 倒是沒聽過KiB MiB 等 現在搞懂 原來分為以1000位元組或用1024位元組來計算之 這就是為什麼我們平時買硬碟或隨身碟的容量與實際真實的容量不同 像是我了8GB的隨身碟 實際為8 3
  • git 建立分支仓库

    Git 命令版本 查看本地分支及追踪 找一个文件夹目录 clone 仓库 Git branch vv 查看所有分支 Git branch a 查看本地分支 git branch 查看远程分支 git branch r 创建本地分支dev g

随机推荐

  • shell脚本编程 实例讲解(键盘输入三个数字,按照从大到小的书顺序输出)

    1 键盘输入三个数字 按照从大到小的书顺序输出 排序题 a b c 2 10 9 a 2 b 10 c 9 第一步 两两相互进行比较 比较三次 第二步 不论谁大谁小 最后都输出 a b c 从大从小 a永远存储的都是最大值 a和b进行比较
  • 笔记&代码

    可视化前三步走 数据类型 分析目的 实现工具 2 1 类别数据可视化 显示各类别的绝对频数及百分比等 条形图 饼图等 2 1 1 条形图及其变种 垂直条形图 类别在x轴 水平条形图 类别在y轴 简单条形图 并列条形图 堆叠条形图 1 简单条
  • 前端知识——css 之 flex 布局

    目录 一 认识 flex 布局 1 flex 布局的重要概念 二 flex 相关属性 1 flex container 中的属性 1 1 flex direction item 的排布方向 1 2 flex wrap 排布是否换行 1 3
  • Java多线程下载文件

    Java多线程下载文件 优化 合理利用服务器资源 将资源利用最大化 加快下载速度 一般有两种方式 线程池里面有N个线程 多线程下载单个文件 将网络路径的文件流切割成多快 每个线程下载一小部分 然后写入到文件里面 组成一个文件 当有很多个文件
  • MQ队列消息怎么保证100%不丢失

    面试官在面试候选人时 如果发现候选人的简历中写了在项目中使用了 MQ 技术 如 Kafka RabbitMQ RocketMQ 基本都会抛出一个问题 在使用 MQ 的时候 怎么确保消息 100 不丢失 这个问题在实际工作中很常见 既能考察候
  • javaScript基础面试题 --- new操作符具体做了什么?

    当我们使用new操作符调用函数时 背后发生了很多事情 这里是简单的new操作符的行为 创建一个新的空对象 将这个空对象的原型链接到构造函数的prototype对象 使用这个新对象作为上下文 即this的值 调用该构造函数 如果构造函数返回一
  • Yii Framework 开发教程(25) 数据库-Query Builder示例

    上一篇介绍PHP使用DAO 数据库访问对象接口 访问数据库的方法 使用DAO需要程序员编写SQL语句 对于一些复杂的SQL语句 Yii提供了Query Builder来帮助程序员生成SQL语句 Query Builder提供了一中面向对象的
  • Windows7安装docker以及使用docker安装centos7

    目录 一 WIN7安装DOCKER 二 docker安装centos7 1 查看可用的 CentOS 版本 2 拉取指定版本的 CentOS 镜像 3 查看本地镜像 4 运行容器 并且可以通过 exec 命令进入 CentOS 容器 5 安
  • STM32内部参考电压+DMA精准采集电池电压

    最近项目又遇到了电池电压采集 锂电池的电压范围是4 2到2 8一般 当锂电池低于3 3V时 单片机供电电压会小于3 3V 那么电池电压参考计算4096就不能对应3 3 所以必须采用内部参考电压 我项目中用到的是RP104N331 LDO 实
  • openwrt上nginx启动报错nginx: [emerg] getpwnam("www") failed

    检查nginx的配置文件 etc nginx nginx conf 里面配置里确实有这一项 user nobody nogroup user www www worker processes 2 系统的用户又没有www这个用户 这就尴尬了
  • 本地缓存技术分享

    本地缓存 缓存分为本地缓存与分布式缓存 本地缓存为了保证线程安全问题 一般使用ConcurrentMap的方式保存在内存之中 而常见的分布式缓存则有Redis MongoDB等 一致性 本地缓存由于数据存储于内存之中 每个实例都有自己的副本
  • 深度学习&强化学习&进化计算 入门资源整理

    深度学习 强化学习 进化计算 入门资源整理 深度学习 在线课程 在线书籍 学习Python 强化学习 在线课程 在线书籍 更多资源 进化计算 后记 深度学习 在线课程 深度学习是机器学习领域的一个分支 想要入门深度学习 最好先对机器学习的一
  • 学会了,不会ps也能更换自己的证件照底色,制作自己的证件照

    证件照经常会由于背景色与要求不符而不能用 再去拍一组浪费时间和金钱 如何省时省力的把照片背景色修改成我们所需要的底色呢 说到修改照片背景色 首先想到大家常用的证件照 根据不同用处会要求 白 蓝 红 底色 在过去大家可能需要去图片社重新照 或
  • [631]一行js代码识别Selenium+Webdriver

    文章目录 一行js代码识别Selenium Webdriver 如何正确移除Selenium中的 window navigator webdriver 最新版 附一些网站检测selenium的示例 driver execute script
  • ESP32 SIM800L:发送带有传感器读数的文本消息(SMS警报)

    在这个项目中 我们将使用T Call ESP32 SIM800L模块创建一个SMS通知系统 当传感器读数高于或低于特定阈值时 该模块会发送SMS 在此示例中 我们将使用DS18B20温度传感器 并在温度高于28 C时发送短信 一旦温度降低到
  • uniapp使用scroll-view实现左右,上下滑动

    uniapp使用scroll view实现左右 上下滑动 阐述 我们在项目中往往都能遇到实现左右滑动跟上下滑动的需求 不需要安装better scroll uniapp 自带的scroll view 就可以实现了 实现左右滑动
  • 开源项目,源码

    GitHub 优秀的 Android 开源项目 转自 http blog csdn net shulianghan article details 18046021 主要介绍那些不错个性化的View 包括ListView ActionBar
  • java基础03:final

    说明 final是java的一个关键字 是最终的意思 final 表示 最后的 最终的 含义 变量一旦赋值后 不能被重新赋值 被 final 修饰的实例变量 就是已经实例化的对象 必须显式指定初始值 final 修饰符通常和 static
  • Flash钓鱼->CS上线(免杀过火绒、360等)

    先看结果 访问钓鱼页面 点击立即升级即把马儿下载下来了 这个马儿是rar压缩的 做成的rar解压自启动 所以是个exe的文件 然后这里为了像一点 把图标给改了 双击运行 查看效果 首先CS是没东西的 解压路径现在也是没东西的 这里我把解压路
  • C#值参数和引用参数

    C 值参数和引用参数 一 值参数 未用ref或out修饰符声明的参数为值参数 使用值参数 通过将实参的值复制到形参的方式 把数据传递到方法 方法被调用时 系统做如下操作 在栈中为形参分配空间 复制实参到形参 值参数的实参不一定是变量 它可以