C# 中ref 与 out 总结

 

  参数的传递一般分为两种:一种是“值传递”即:传递实参的拷贝,既然是拷贝那么在函数中对这个形参所作的任何动作都不会反映到原来的实参中。另外一种是“引用传递”即:传递实参的地址(形参和实参指向同一块内存地址),那么在函数中对形参所作的任何改变都要反映到原来的实参中。

  在C#中实现“引用传递”的两种方式为:ref 和 out。当然这两种方式也有他们的不同,下面将逐步讲解他们的不同之处。

  1. 使用ref关键字进行“引用传递”时,传入的实参必须先被初始化,这就像C和C++中的指针一样,一定要先给它赋值(让它指向一个指定的内存位置),要不然它不一定会指向内存的哪里,这样很危险,不允许。而使用out关键字进行“引用传递”时,传入的实参不必先初始化。如下面的例子所示:

    
     1using System;
    2using System.Collections.Generic;
    3using System.Linq;
    4using System.Text;
    5
    6namespace RefAndOut
    7{
    8 class RefAndOutTesting
    9 {
    10 static void Main(string[] args)
    11 {
    12 int x;
    13 int y;
    14 OutTest(out x, out y);
    15 Console.WriteLine(string.Format("x = {0}, y = {1}", x, y));
    16
    17 int a = 100;
    18 int b = 200;
    19 RefTest(ref a, ref b);
    20 Console.WriteLine(string.Format("a = {0}, y = {1}", a, b));
    21 }
    23 //out参数在使用前不必初始化
    24 public static void OutTest(out int first, out int second)
    25 {
    27 first = 1;
    28 second = 2;
    29 }
    30 //ref参数在使用前必须初始化
    31 public static void RefTest(ref int first, ref int second)
    32 {
    33 first = 1111;
    34 second = 2222;
    35 }
    36 }
    37}
  2. 虽然使用out关键字进行“引用传递”时,传入的实参不必先初始化,但是在函数中一定要先对参数进行初始化,之后再使用。因为:在使用out参数的时候,程序首先将out的实参(形参)置空,(因此实质上实参先初始化了对此函数也没有用)然后再对参数进行相应的操作;由于置空了,所以在离开该函数之前必须完成参数的初始化(即使你不对参数做任何操作),要不然该参数的指针又不知道该指向何处了。假如变化一下上面的OutTest函数:
    1         public static void OutTest(out int first, out int second)
    2 {
    3 first = second;
    4 //first = 1;
    5 //second = 2;
    6   }

    便会提示你:Use of unassigned out parmeter 'second'。即使你先初始化实参再去调用也会出现同样的错误(原因就是out先对参数进行清空操作)

    
     1 using System;
    2  using System.Collections.Generic;
    3  using System.Linq;
    4  using System.Text;
    5
    6  namespace OutAndRef
    7 {
    8 class Program
    9 {
    10 static void Main(string[] args)
    11 {
    12 //out变量在使用之前不必进行显示的赋值
    13 int x = 1111;
    14 int y = 2222;
    15 OutTest(out x, out y);
    16 Console.WriteLine("x = {0}, y = {1}", x, y);
    17 }
    18
    20 public static void OutTest(out int first, out int second)
    21 {
    22 //离开这个函数前,必须对first和second赋值,否则会报错。
    23 first = second;
    24 //上面这行会报错,因为使用了out后,first和second都清空了,需要重新赋值,即使调用函数前赋过值也不行
    25 first = 1;
    26 second = 2;
    27 }
    29 }
    31 }
    32
  3. 因此上面的两点可以总结为:ref有出有进,out有出没进。
  4. 使用ref和out进行“引用传递”,在定义方法和调用方法时,都要在参数前加ref和out关键字,以满足匹配。
  5. 由于属性是方法,不是变量;而指针是变量。所以属性都不可以作为ref和out参数传递。如果在上面的RefAndOutTesting类中声明两个属性,传递给RefTest和OutTest方法中,则会出错!
    
     1 using System;
    2 using System.Collections.Generic;
    3 using System.Linq;
    4 using System.Text;
    5
    6 namespace RefAndOut
    7 {
    8 class RefAndOutTesting
    9 {
    10 //属性(是方法,不是变量)所以不可以作为ref和out参数
    11 public static int firstNumber
    12 {
    13 get;
    14 set;
    15 }
    16 public static int secondNumber
    17 {
    18 get;
    19 set;
    20 }
    21
    22 //字段可以作为ref和out参数
    23 public static int myNumber;
    24 public static int yourNumber;
    25
    26 static void Main(string[] args)
    27 {
    28 //正确
    29 OutTest(out myNumber, out yourNumber);
    30 Console.WriteLine(  "myNumber = {0}, yourNumber = {1}", myNumber, yourNumber);
    31 RefTest(ref myNumber, ref yourNumber);
    32 Console.WriteLine( "myNumber = {0}, yourNumber = {1}", myNumber, yourNumber);
    33
    34 //错误
    35 OutTest(out firstNumber, out secondNumber);
    36 Console.WriteLine("firstNumber = {0}, secondNumber = {1}", firstNumber, secondNumber);
    37 RefTest(ref firstNumber, ref secondNumber);
    38 Console.WriteLine("firstNumber = {0}, secondNumber = {1}", firstNumber, secondNumber);
    45 }
    46 }
    47 }

C# ref和out总结的更多相关文章

  1. .NET 基础一步步一幕幕[out、ref、params]

    out.ref.params out: 如果你在一个方法中,返回多个相同类型的值的时候,可以考虑返回一个数组. 但是,如果返回多个不同类型的值的时候,返回数组就不行了,那么这个时候, 我们可以考虑使用 ...

  2. out和ref详解

    要想充分理解C# out和ref,必须先明确如下两个概念(对值类型与引用类型掌握比较好的,可以跳过"一.明确两个基本概念") 一.明确两个基本概念 值类型: 定义:通过值的方式来传 ...

  3. c#编程基础之ref、out参数

    引例: 先看这个源码,函数传递后由于传递的是副本所以真正的值并没有改变. 源码如下: using System; using System.Collections.Generic; using Sys ...

  4. C#中out和ref之间的区别【转】

    首先:两者都是按地址传递的,使用后都将改变原来参数的数值. 其次:ref可以把参数的数值传递进函数,但是out是要把参数清空,就是说你无法把一个数值从out传递进去的,out进去后,参数的数值为空,所 ...

  5. 通过一个实例重新认识引用类型,值类型,数组,堆栈,ref

    昨天在写代码时候遇到了一个问题,百思不得其解,感觉颠覆了自己对C#基础知识的认知,因为具体的情境涉及公司代码不便放出,我在这里举个例子,先上整个测试所有的代码,然后一一讲解我的思考过程: using ...

  6. 图解C#的值类型,引用类型,栈,堆,ref,out

    C# 的类型系统可分为两种类型,一是值类型,一是引用类型,这个每个C#程序员都了解.还有托管堆,栈,ref,out等等概念也是每个C#程序员都会接触到的概念,也是C#程序员面试经常考到的知识,随便搜搜 ...

  7. 异步方法不能使用ref和out的解决方法

    异常处理汇总-后端系列:http://www.cnblogs.com/dunitian/p/4523006.html 应用场景==>后端现在都是用异步方法,那么分页是必不可少的,于是就有了这个问 ...

  8. [C#]浅析ref、out参数

    转载:http://www.cnblogs.com/vd630/p/4601919.html#top 按引用传递的参数算是C#与很多其他语言相比的一大特色,想要深入理解这一概念应该说不是一件容易的事, ...

  9. C#基础-out与ref字段

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Cons ...

  10. C# out ref 重载

    今天看极客学院wiki时候看到了out,ref的介绍,之前对这个知识点没有深刻认识,所以就写了个小测试看了下,瞬间明白了. using System; using System.Collections ...

随机推荐

  1. 博弈 Nim问题 POJ2234

    定义: 通常的Nim游戏的定义是这样的:有若干堆石子,每堆石子的数量都是有限的,合法的移动是 “选择一堆石子并拿走若干颗(不能不拿)”,如果轮到某个人时所有的石子堆都已经被拿空了, 则判负(因为他此刻 ...

  2. bzoj4950(二分图最大匹配)

    [Wf2017]Mission Improbable Time Limit: 1 Sec  Memory Limit: 1024 MBSubmit: 105  Solved: 49[Submit][S ...

  3. [NOIP2001] 提高组 洛谷P1025 数的划分

    题目描述 将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序). 例如:n=7,k=3,下面三种分法被认为是相同的. 1,1,5; 1,5,1; 5,1,1; 问有多少种不同的分法. 输 ...

  4. 【搜索引擎】SOLR VS Elasticsearch(2019技术选型参考)

    SOLR是什么 (官方的解释) Solr是基于Apache Lucene构建的流行的.快速的.开源的企业搜索平台. Solr也是高度可靠.可伸缩和容错的,提供分布式索引.复制和负载平衡查询.自动故障转 ...

  5. Linux--进程组、会话、守护进程(转)

    http://www.cnblogs.com/forstudy/archive/2012/04/03/2427683.html 进程组 一个或多个进程的集合 进程组ID: 正整数 两个函数 getpg ...

  6. Codeforces 920E(补图BFS)

    题意: n(n<=200000)个点的完全图删去了m(m<=200000)条边,求剩下图的连通分量. 分析: 将未访问过的点用一个链表串起来 仍旧进行BFS,每次BFS扩展一个点u的时候, ...

  7. Java并发编程,3分分钟深入分析volatile的实现原理

    volatile原理 volatile简介 Java内存模型告诉我们,各个线程会将共享变量从主内存中拷贝到工作内存,然后执行引擎会基于工作内存中的数据进行操作处理. 线程在工作内存进行操作后何时会写到 ...

  8. Hibernate学习笔记(三)

    我是从b站视频上学习的hibernate框架,其中有很多和当前版本不符合之处,我在笔记中进行了修改以下是b站视频地址:https://www.bilibili.com/video/av14626440 ...

  9. Java子类重写父类方法注意问题收集(转)

    子类不能重写父类的静态方法,私有方法.即使你看到子类中存在貌似是重写的父类的静态方法或者私有方法,编译是没有问题的,但那其实是你重新又定义的方法,不是重写.具体有关重写父类方法的规则如下: 重写规则之 ...

  10. MD5加密Java工具类

    原文:http://www.open-open.com/code/view/1421764946296 import java.security.MessageDigest; public class ...