西西软件下载最安全的下载网站、值得信赖的软件下载站!

首页编程开发C#.NET → c# 引用类型方法参数的关键字ref深度解析

c# 引用类型方法参数的关键字ref深度解析

相关软件相关文章发表评论 来源:西西整理时间:2012/11/21 14:46:13字体大小:A-A+

作者:西西点击:0次评论:0次标签: 引用类型

昨天在垒代码的时候遇到了一个基础没打牢就会暴露的问题。传递给方法的参数为类(class)时,在方法中所做的修改赋值不一定会最终改变到原始的变量上。

举一个例子,如果一个方法Action(List<int> lst),在方法里面对lst做了很多操作,包括add,remove,new,add等等。传入变量List<int> input,方法执行完之后,input可能被执行了add,remove,但是new以后的任何操作都没有保留。这是为什么呢?最开始学习.net基础的时候就知道,引用类型,传递给方法的是引用的地址,而不是实际数值。那为什么会部分的操作被保留了出来,而部分又没有执行呢?

用代码来分析此案例:

static void Main(string[] args)
{   
    int i = 0;
    int refI = 0;
    List<int> list = new List<int>() { 0, 1, 2 };
    List<int> refList = new List<int>() { 0, 1, 2 };
    testStruct(i);
    TestRefStruct(ref refI);
    TestClass(list);
    TestRefClass(ref refList);
    Console.WriteLine("i: {0}\r\nrefI: {1}\r\nlist: {2}\r\nrefList: {3}", i, refI,
      list.Select(x => x.ToString()).Aggregate((x, y) => x + "," + y),
      refList.Select(x => x.ToString()).Aggregate((x, y) => x + "," + y));
    Console.ReadKey();
}

static void TestStruct(int input)
{
    input = 10;
}

static void TestRefStruct(ref int input)
{
    input = 10;
}

static void TestClass(List<int> input)
{
    input.Add(5);
    input = new List<int>();
    input.Add(10);
}

static void TestRefClass(ref List<int> input)
{
    input.Add(5);
    input = new List<int>();
    input.Add(10);
}

调试程序,最后输出

i: 0
refI: 10
list: 0,1,2,5
refList: 10

在函数TestStruct中,传入一个值类型的参数,没有对传递进去的参数i做任何的修改。

在函数TestRefStruct中,传入值类型的参数,通过引用传递参数ref,函数中对input进行的任何改变都影响到了refI上,所做的编辑修改全部保留过来。最终refI的值为10。

在函数TestClass中,传入一个引用类型的参数,在函数中,对input重新赋值之前所做的修改都保留了下来,影响了list的值。而在对input重新赋值之后的所有修改编辑,都和list没有任何关联了。

在函数TestRefClass中,传入一个引用类型的参数,同时,参数前面加上ref的约束,函数中,对input进行的任何编辑都影响了refList。最终refList的值为new List<int>{ 10 }。

有一定.net基础的人都可以很清晰的理解第一、二和第四种情况。但是第三种情况常常会给我们留下陷阱。

如何理解和正确的对待函数传递的参数为引用类型的情况?我的理解是:

第三种情况下,传递给函数的变量A提供的是一个引用地址,函数会自动生成一个变量B,同时用传递进来的引用地址对这个变量B赋值,这时,传递进来的变量A和函数内调用的变量B共一个引用地址,所做的修改会同步的影响另一个参数。如果在函数内部,出现了一个input = new List<int>();的语句。这时,变量B会重新赋值到另一个引用地址。那么,从此之后,变量B与变量A再没有关联,对变量B所做的任何修改将不影响变量A。

下面模拟代码呈现:

List<int> A = new List<int>() { 0, 1, 2 };//传递给函数的变量。

{//进入函数
    List<int> B = A;//函数执行后,自动生成B,同时用A对B赋值。
    B.Add(5);//由于他们是引用类型,共一个引用地址,所做修改相互影响。此时A的值也一起改变。
    B = new List<int>();//对B重新赋值,指向另一个引用地址。与A无关。
    B.Add(10);//A不变。
}//出函数,B释放,A继续存在。

个人理解。如果不足请补充。

    相关评论

    阅读本文后您有什么感想? 已有人给出评价!

    • 8 喜欢喜欢
    • 3 顶
    • 1 难过难过
    • 5 囧
    • 3 围观围观
    • 2 无聊无聊

    热门评论

    最新评论

    第 2 楼 北京市零度聚阵银河世纪网吧 网友 客人 发表于: 2013/5/6 11:17:24
    好高深的东东

    支持( 0 ) 盖楼(回复)

    第 1 楼 重庆市忠县 网友 客人 发表于: 2013/7/14 11:16:57
    继续加油

    支持( 0 ) 盖楼(回复)

    发表评论 查看所有评论(0)

    昵称:
    表情: 高兴 可 汗 我不要 害羞 好 下下下 送花 屎 亲亲
    字数: 0/500 (您的评论需要经过审核才能显示)