当前位置: 首页 > news >正文

C# ref 和 out 的使用详解

总目录


前言

在 C# 编程中,ref 和 out 是两个非常重要的关键字,它们都用于方法参数的传递,但用途和行为却有所不同。今天,我们就来深入探讨一下这两个关键字的用法和区别,让你在编程中能够得心应手地使用它们。


一、什么是 ref 和 out?

在 C# 中,方法的参数默认是通过值传递的,这意味着方法内部对参数的修改不会影响到外部的变量。但有时候,我们希望方法能够修改外部变量的值,或者需要返回多个值。这时候,ref 和 out 就派上用场了。

  • ref:表示引用传递。它允许方法修改传入的变量的值,并且这些修改会反映到外部变量上。
  • out:也表示引用传递,但它主要用于返回多个值。与 ref 不同的是,out 参数在传入方法之前不需要初始化。

二、传值赋值和传址赋值

  • 传值赋值:赋值运算符操作的是值类型数据或字符串
  • 传址/引用赋值:赋值运算符操作的是引用类型数据,除字符串
class User
{public string Id { get; set; }public string Name { get; set; }public string Sex { get; set; }
}class Program
{static void Main(){// 值类型 和 string int num = 10;string text = "hello";ChangeValue(num,text);Console.WriteLine(num);  // 输出10,原值纹丝不动!Console.WriteLine(text); // 输出hello,原值纹丝不动!// 引用类型 除 stringUser user = new User() { Id = "1", Name = "鲲籽鲤", Sex = "男" };UpdateUser(user);Console.WriteLine($"User.Id={user.Id},User.Name={user.Name}");// 输出:User.Id=2,User.Name=鲤籽鲲}static void ChangeValue(int x,string str){x = 100;str = "ni hao";}static void UpdateUser(User user){user.Id = "2";user.Name = "鲤籽鲲";}
}

通过以上案例可知:

  • 在对值类型以及字符串进行赋值的时候,是将值进行的复制。
  • 在对引用类型(除字符串)进行赋值的时候,是将数据内容的索引或地址进行的复制

二、ref 的使用

1. 基本用法

ref 参数必须在调用方法之前初始化。我们来看一个简单的例子:

public void IncreaseValue(ref int value)
{value += 10;
}// 调用示例
int myNumber = 5;
IncreaseValue(ref myNumber);
Console.WriteLine(myNumber); // 输出:15

在这个例子中,myNumber的值被方法IncreaseValue增加到了15。因为ref传递的是引用,所以对value的任何修改都会反映到myNumber上。

public void Swap(ref int a, ref int b)
{int temp = a;a = b;b = temp;
}int x = 10;
int y = 20;
Swap(ref x, ref y);
Console.WriteLine($"x: {x}, y: {y}"); // 输出:x: 20, y: 10

在这个例子中,Swap 方法通过 ref 参数交换了两个整数的值。调用方法时,我们需要在参数前加上 ref 关键字,并且变量 x 和 y 必须在调用之前初始化。

2. 注意事项

  • 必须初始化:ref 参数在传入方法之前必须被赋值,否则会报编译错误。
  • 修改外部变量:ref 参数允许方法修改外部变量的值,这可能会导致意外的副作用,所以使用时要小心。

三、out 的使用

1. 基本用法

out 参数主要用于返回多个值,它在传入方法之前不需要初始化,但方法内部必须为 out 参数赋值。来看一个例子:

public void GetMinMax(int[] numbers, out int min, out int max)
{min = numbers[0];max = numbers[0];foreach (int num in numbers){if (num < min) min = num;if (num > max) max = num;}
}int[] numbers = { 5, 2, 9, 1, 7 };
int min, max;
GetMinMax(numbers, out min, out max);
Console.WriteLine($"Min: {min}, Max: {max}"); // 输出:Min: 1, Max: 9

在这个例子中,GetMinMax 方法通过 out 参数返回了数组中的最小值和最大值。调用方法时,我们只需要声明变量 min 和 max,而不需要在调用之前初始化它们。

public void Divide(int dividend, int divisor, out int quotient, out int remainder)
{quotient = dividend / divisor;remainder = dividend % divisor;
}// 调用示例
Divide(10, 3, out int quotient, out int remainder);
Console.WriteLine($"Quotient: {quotient}, Remainder: {remainder}");
// 输出:Quotient: 3, Remainder: 1

Divide方法不仅计算了商(quotient),还计算了余数(remainder)。注意,我们在调用时声明了两个out变量,并且在方法内部都进行了赋值。

2. 注意事项

  • 无需初始化:out 参数在传入方法之前不需要初始化,方法内部必须为 out 参数赋值。
  • 返回多个值:out 参数非常适合用于返回多个值,但过多的 out 参数可能会使代码变得复杂,可读性降低。

四、ref 和 out 的区别

特性refout
初始化要求必须在传入方法之前初始化不需要初始化,方法内部必须赋值
方法内赋值可改可不改
方法内可以不修改值(但通常建议修改)
必须赋值
用途修改外部变量的值返回多个值
调用方式调用时和方法定义时都需要加 ref调用时和方法定义时都需要加 out
语义输入输出纯输出
  • 使用ref可以让方法读取和修改传入参数的值,但需要先初始化。
  • 使用out可以在方法中返回额外的结果,而不需要提前初始化参数,但方法内必须对out参数赋值。
  • out 更侧重输出,即是说将传进方法的参数,自行在内部赋值,然后给到外部使用,正因它是必须在内部赋值,所以它不在乎该变量是否有初始值
  • ref 更侧重修改,即是说传进方法的参数本身就有值,在方法内部对变量值进行修改,它只是对变量的值进行修改,因此他要求变量必须有初始值

五、应用场景

1. TryParse模式(经典out用法):

if(int.TryParse("123", out var result))
{// 安全使用result
}

2. 大结构体优化(ref高级用法):

void 处理大结构(ref BigStruct data)
{// 避免值类型复制开销
}

3. Swapper工具(ref炫技):

void Swap(ref int a, ref int b)
{(a, b) = (b, a);
}

五、in 关键字(补充)

从 C# 7.2 开始,引入了 in 关键字。它用于传递只读引用,方法内部不能修改传入的参数值。这在传递大型结构体时可以提高性能,同时保证数据的安全性。

public void Print(in Person person)
{Console.WriteLine(person.Name);// person.Name = "New Name"; // 编译错误,不能修改
}

六、注意事项

  • 用out时代替多返回值更优雅
  • 异步方法中禁止使用
  • 属性不能作为参数传递(编译直接报错)
  • 重载方法时ref和out算不同签名
  • ref适用:游戏角色属性修改、实时数据更新
  • out适用:数据解析、状态检测返回多值

结语

回到目录页:C#/.NET 知识汇总
希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。

相关文章:

C# ref 和 out 的使用详解

总目录 前言 在 C# 编程中&#xff0c;ref 和 out 是两个非常重要的关键字&#xff0c;它们都用于方法参数的传递&#xff0c;但用途和行为却有所不同。今天&#xff0c;我们就来深入探讨一下这两个关键字的用法和区别&#xff0c;让你在编程中能够得心应手地使用它们。 一、什…...

Ubuntu 24.04.1 LTS 本地部署 DeepSeek 私有化知识库

文章目录 前言工具介绍与作用工具的关联与协同工作必要性分析 1、DeepSeek 简介1.1、DeepSeek-R1 硬件要求 2、Linux 环境说明2.1、最小部署&#xff08;Ollama DeepSeek&#xff09;2.1.1、扩展&#xff08;非必须&#xff09; - Ollama 后台运行、开机自启&#xff1a; 2.2、…...

用 WOW.js 和 animate.css 实现动画效果

用 wow.js 就可以实现动画效果&#xff0c;但由于里面的动画样式太少&#xff0c;一般还会引入 animated.css 第一步&#xff1a;下载 选择合适的包管理器下载对应的内容 pnpm i wow.js animated.css --save 第二步&#xff1a;引入 在main.js中加入&#xff1a; import …...

1-知识图谱-概述和介绍

知识图谱&#xff1a;浙江大学教授 陈华军 知识图谱 1课时 http://openkg.cn/datasets-type/ 知识图谱的价值 知识图谱是有什么用&#xff1f; 语义搜索 问答系统 QA问答对知识图谱&#xff1a;结构化图 辅助推荐系统 大数据分析系统 自然语言理解 辅助视觉理解 例…...

flink jobgraph详细介绍

一、Flink JobGraph 的核心概念 JobGraph 是 Flink 作业的核心执行计划&#xff0c;它描述了作业的任务拓扑结构和数据流关系。JobGraph 由以下几部分组成&#xff1a; 顶点&#xff08;Vertex&#xff09; 每个顶点代表一个任务&#xff08;Task&#xff09;&#xff0c;例如…...

使用nginx+rtmp+ffmpeg实现桌面直播

使用nginxrtmpffmpeg实现桌面直播 流媒体服务器搭建 docker run docker镜像基于添加了rtmp模块的nginx&#xff0c;和ffmpeg docker pull alfg/nginx-rtmp docker run -d -p 1935:1935 -p 8080:80 --namenginx-rtmp alfg/nginx-rtmprtmp模块说明 进入容器内部查看 docker…...

每日一题——将数字字符串转化为IP地址

将数字字符串转化为IP地址 题目描述解题思路回溯法步骤分解 代码实现全局变量有效性验证函数回溯函数主函数完整代码 复杂度分析关键点说明总结 这题难度还挺大的&#xff0c;整体上实现并不容易。建议参考视频 和https://programmercarl.com/0093.%E5%A4%8D%E5%8E%9FIP%E5%9C%…...

机器学习数学基础:25.随机变量分布详解

一、随机变量与分布函数的基本概念 &#xff08;一&#xff09;什么是随机变量&#xff1f; 在概率论领域&#xff0c;随机变量是将随机试验的结果进行数值化的关键概念。它就像一座桥梁&#xff0c;把抽象的随机事件和具体的数学分析连接起来。 举例来说&#xff0c;在一个…...

香港电讯与Zenlayer达成战略合作,拓展全球互联生态圈

作为主要国际金融与贸易中心&#xff0c;香港一直是连系中国内地及全球市场的重要门户。香港电讯作为本地领先的综合电讯服务提供商&#xff0c;拥有广泛的网络资源和深厚的技术专长&#xff0c;一直支持国内企业“走出去”和外资企业“走进来”。而旗下由PCCW Global营运的Con…...

MySQL-事务隔离级别

事务有四大特性&#xff08;ACID&#xff09;&#xff1a;原子性&#xff0c;一致性&#xff0c;隔离性和持久性。隔离性一般在事务并发的时候需要保证事务的隔离性&#xff0c;事务并发会出现很多问题&#xff0c;包括脏写&#xff0c;脏读&#xff0c;不可重复读&#xff0c;…...

【Python学习 / 6】面向对象编程(OOP)

文章目录 ⭐前言⭐一、类和对象&#xff1a;面向对象编程基础1. 类&#xff08;Class&#xff09;类的组成&#xff1a;例子&#xff1a;定义一个简单的 Dog 类代码解析&#xff1a; 2. 对象&#xff08;Object&#xff09;对象的创建&#xff1a; 3. 三大特性&#xff1a;封装…...

Ollama DeepSeek + AnythingLLM 实现本地私有AI知识库

Ollama DeepSeek AnythingLLM 实现本地私有AI知识库 本地部署DeepSeek-r1下载安装AnythingLLMAnythingLLM 配置LLM首选项Embedder首选项向量数据库工作区其他配置 AnythingLLM Workspace使用上传知识词嵌入知识检索 本文主要介绍了如何使用AnythingLLM结合Ollama部署的DeepSee…...

个人博客测试报告

一、项目背景 个人博客系统采用前后端分离的方法来实现&#xff0c;同时使用了数据库来存储相关的数据&#xff0c;同时将其部署到云服务器上。前端主要有四个页面构成&#xff1a;登录页、列表页、详情页以及编辑页&#xff0c;以上模拟实现了最简单的个人博客系统。其结合后…...

嵌入式八股文(四)计算机网络篇

第一章 基础概念 1. 服务 指网络中各层为紧邻的上层提供的功能调用,是垂直的。包括面向连接服务、无连接服务、可靠服务、不可靠服务。 2. 协议 是计算机⽹络相互通信的对等层实体之间交换信息时必须遵守的规则或约定的集合。⽹络协议的三个基本要素:语法、…...

基于Electron+Vue3创建桌面应用

Electron 是一个开源框架,基于 Chromium 和 Node.js,用于开发跨平台桌面应用程序。它允许开发者使用 HTML、CSS 和 JavaScript 等 Web 技术构建原生桌面应用,支持 Windows、macOS 和 Linux。Electron 以其开发便捷性、强大的功能和丰富的生态系统而广泛应用于工具类应用、媒…...

建立稳定分析模式的模式语言01

Haitham Hamza 等 著&#xff0c;wnb 译 摘要 一般认为&#xff0c;软件分析模式在减少开销和缩短软件产品生命周期等方面会起到重要的作用。然而&#xff0c;分析模式的巨大潜能还未被充分发掘。缺乏稳定性是当前分析模式存在的主要问题。多数情况下&#xff0c;为特定问题建…...

【C++游戏开发-五子棋】

使用C开发五子棋游戏的详细实现方案&#xff0c;涵盖核心逻辑、界面设计和AI对战功能&#xff1a; 1. 项目结构 FiveChess/ ├── include/ │ ├── Board.h // 棋盘类 │ ├── Player.h // 玩家类 │ ├── AI.h // AI类 │ └── Game.h // 游戏主逻辑 ├── src/ …...

ubuntu20动态修改ip,springboot中yaml的内容的读取,修改,写入

文章目录 前言引入包yaml原始内容操作目标具体代码执行查看结果总结: 前言 之前有个需求&#xff0c;动态修改ubuntu20的ip&#xff0c;看了下&#xff1a; 本质上是修改01-netcfg.yaml文件&#xff0c;然后执行netplan apply就可以了。 所以&#xff0c;需求就变成了 如何对ya…...

tailwindcss学习02

vue中接入tailwindcss 使用cmd不要使用powershell npm create vitelatest stu02 -- --template vue cd stu02npm install --registry http://registry.npm.taobao.org npm install -D tailwindcss3.4.17 postcss autoprefixer --registry http://registry.npm.taobao.org npx t…...

千峰React:脚手架准备+JSX基础

组件化->封装性 React提供函数组件实现组件化 React和传统JS的区别就是JS需要手动管理DOM操作&#xff0c;React: 采用组件化开发&#xff0c;通过虚拟DOM提升性能。 MVC 是一种软件设计模式&#xff0c;全称为 Model-View-Controller&#xff08;模型-视图-控制器&#x…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...