C#中ref和out的区别浅析
作者:junjie 发布时间:2021-12-22 23:00:50
在C#中通过使用方法来获取返回值时,通常只能得到一个返回值。因此,当一个方法需要返回多个值的时候,就需要用到ref和out,那么这两个方法区别在哪儿呢?
MSDN:
ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。
out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字。
案例:
定义一个方法,求一个整数数组中的最大值,最小值,和,平均数。如果是一个方法只能有一个返回值,那只能每一个都得定义一个方法来实现,不过有了ref和out这实现起来就方便多了。
ref:
static int GetIntResult(int[] arry, ref float avg, ref int max, ref int min)
{
int sum = 0;
max = arry[0];
min = arry[0];
for (int i = 0; i < arry.Length; i++)
{
sum += arry[i];
if (max < arry[i])
{
max = arry[i];
}
if (min > arry[i])
{
min = arry[i];
}
}
avg = sum / arry.Length;
return sum;
}
然后在控制台中试着调用该方法:
static void Main(string[] args)
{
int[] arr = { 1,2,3,4,5,6,7,8,9};
float avg;
int max;
int min;
int sum = GetIntResult(arr, ref avg, ref max, ref min);
}
此时编译器就会提示画红线,错误:使用了未赋值的avg,max,min
static void Main(string[] args)
{
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
float avg = 0;
int max = 0;
int min = 0;
int sum = GetIntResult(arr, ref avg, ref max, ref min);
Console.WriteLine("和:{0}\t平均值:{1}\t最大值:{2}\t最小值:{3}", sum, avg, max, min);
Console.Read();
}
运行结果:
总结:
ref这个关键字告诉c#编译器被传递的参数值指向与调用代码中变量相同的内存。这样,如果被调用的方法修改了这些值然后返回的话,调用代码的变量也就被修改了。
ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中(avg,max,min的初始值为0,调用方法后值改变)。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。
out:
换成out之后,上面的方法不再适用,报错,错误 : 控制离开当前方法之前必须对 out 参数“min”和"max"赋值。你会发现这里max和min在循环外并未初始化。所以才会出错。
修改后代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Wolfy.RefAndOut
{
class Program
{
static void Main(string[] args)
{
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
float avg;//在使用out关键字时,不需要在此处初始化,初始化也不会影响到方法内部的值,所以你初始化没用
int max;
int min;
int sum = GetIntResult(arr, out avg, out max, out min);
Console.WriteLine("和:{0}\t平均值:{1}\t最大值:{2}\t最小值:{3}", sum, avg, max, min);
Console.Read();
}
static int GetIntResult(int[] arry, out float avg, out int max, out int min)
{
int sum = 0;
max = arry[0];
min = arry[0];//使用out关键字时,必须在离开方法前对out关键字修饰的参数初始化
for (int i = 0; i < arry.Length; i++)
{
sum += arry[i];
if (max < arry[i])
{
max = arry[i];
}
if (min > arry[i])
{
min = arry[i];
}
}
avg = sum / arry.Length;
return sum;
}
}
}
结果和上面一样。
总结:
out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字。
结论:
关键字“ref“和”out”之间的唯一区别就是关键字”out“不要求调用代码初始化要传递的参数值。那么关键字‘ref”什么时候用呢?当您需要确保调用方法已经初始化参数值的时候,您就应该使用关键字“ref”。在上面例子中,能够使用“out“是因为被调用的方法并不依赖于被传递的变量的值。个中滋味慢慢体会......
后话:
在一论坛里面,偶然看到有这样的帖子,就顺便总结了一下,也算是回忆一下c#基础知识吧。


猜你喜欢
- C# AttributeUsage的使用是如何的呢?首先让我们来了解一下什么是AttributeUsage类它是另外一个预定义特性类,Att
- string t = DateTime.Now.Ticks.ToString();  
- fatal error C1003: error count exceeds number; stopping compilation中文对
- C#之委托委托:顾名思义,让别人帮你办件事。委托是C#实现回调函数的一种机制。可能有人会问了,回调函数是个啥???举个例子:我现在是一家公司
- 一、SO库加载原理Java Api 提供以下两个接口加载一个 so 库System. loadLibrary (String libName
- 本文实例为大家分享了java实现查找替换功能的具体代码,供大家参考,具体内容如下查找if(searchTxt.getText().equal
- 答案是能!松哥之前写过类似的文章,但是主要是讲了用法,今天我们来看看原理!本文基于当前 Spring Security 5.3.4 来分析,
- 一、题目描述题目实现:网络资源的断点续传功能。二、解题思路获取要下载的资源网址显示网络资源的大小上次读取到的字节位置以及未读取的字节数输入下
- 目录或库文件名中包含汉字或空格的话,请将其用半角双引号括住。项目、属性、C/C++、附加包含目录:填写附加头文件所在目录 分号间隔多项项目、
- 在 String 中提供了两个截取字符串的方法,一个是从指定位置截取到字符串结尾,另一个是截取指定范围的内容。下面对这两种方法分别进行介绍。
- DateTime dt = DateTime.Now;Label1.Text = dt.ToString();//2005-11-5 13:
- 前言最近做了一个调查问卷导出的功能,需求是将维护的题目,答案,导出成word,参考了几种方案之后,选择功能强大的freemarker+固定格
- 手机一般有两种类型的输入设备。一种是键盘类型的输入设备,通常它包含电源键和音量下键。另一种是触摸类型的输入设备,触摸屏就属于这种类型。键盘类
- 前言我们通常使用Spring boot做项目搭建的基础框架,必然少不了它的内置日志框架Logback,在spring-boot-starte
- java.lang.StackOverflowError出现的原因严重: Exception initializing page conte
- 本文实例为大家分享了android中NFC读写功能的具体代码,供大家参考,具体内容如下首先检查一下设备是否支持NFC功能private vo
- 可能我们用惯了 Newtonsoft.Json.dll 等第三方的类库来实现序列化等类似的操作,但是有时只是简单的用一下,感觉没必要那么费事
- 由于公司平台访问人数逐渐增多,公司项目的数据库已经几次出现宕机现象。为减轻数据库压力,我上个月对公司项目做了下调整。把新闻板块提取出来单独一
- 前言进入到 SpringBoot2.7 时代,有小伙伴发现有一个常用的类忽然过期了:在 Spring Security 时代,这个类可太重要
- 本文要解决在侧滑菜单右边加个文本框,并能实现文本的上下滑动和菜单的左右滚动。这里推荐可以好好看看android的触摸事件的分发机制,这里我就