Rocho.J

人脑是不可靠的, 随时记录感悟并且经常重复!

 

关于引用类型的 ref 传参操作

编码时候不自然的就给引用类型的参数加了个ref, 然后突然意识到: 加不加有区别吗? 做了些测试没区别啊....   参考了2篇文章, 最终结论放到图示里边了, 可能更好懂一些.

 

文章一: 

[转] 值类型 引用类型 ref out , 转自; --- http://blog.csdn.net/chuwachen/article/details/7416228

 

值类型主要由两类组成:结构和枚举。结构分为以下几类:Numeric(数值)类型 (整型 浮点型 decimal)bool 用户定义的结构。基于值类型的变量直接包含值。将一个值类型变量赋给另一个值类型变量时,将复制包含的值。这与引用类型变量的赋值不同,引用类型变量的赋值只复制对对象的引用,而不复制对象本身。
引用类型的变量又称为对象,可存储对实际数据的引用。包括:class interface delegate object string
值类型变量直接包含其数据,这与引用类型变量不同,后者包含对其数据的引用。因此,向方法传递值类型变量意味着向方法传递变量的一个副本。方法内发生的对参数的更改对该变量中存储的原始数据无任何影响。如果希望所调用的方法更改参数的值,必须使用 ref 或 out 关键字通过引用传递该参数。

当ref应用于值类型参数时,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。
当ref应用于引用类型参数时,允许被调用的方法修改该引用所引用的对象。
当通过值传递引用类型的参数时,有可能更改引用所指向的数据,如某类成员的值。但是无法更改引用本身的值;也就是说,不能使用相同的引用为新类分配内存并使之在块外保持。若要这样做,应使用 ref 或 out 关键字传递参数。如
      void change(ref MyData data1, MyData data2)
      {
         data1.k = 6;
         data1 = new MyData(10);
         data2.k = 6;
         data2 = new MyData(10);
      }
      void Main(string[] args)
      {
         MyData data_1 = new MyData(8);
         MyData data_2 = new MyData(8);
         change(ref data_1, data_2);
         int k1 = data_1.k; // k1 = 10;
         int k2 = data_2.k; // k2 = 6;
      }

传递到 ref 参数的参数必须最先初始化。这与 out 不同,out 的参数在传递之前不需要显式初始化。尽管 ref 和 out 在运行时的处理方式不同,但它们在编译时的处理方式是相同的。因此,如果一个方法采用 ref 参数,而另一个方法采用 out 参数,则无法重载这两个方法。

 

 

=============

文章二:

[转] C#程序员请不要混淆引用类型和ref引用传参 --- 转自: http://bbs.51aspx.com/showtopic-43537.html

C# ref引用传参
先看一段代码1:

 

       

 

static void Main(string[] args)

        {          

            StringBuilder sb = new StringBuilder("1");

            test(sb);

            Console.WriteLine(sb.ToString());

            Console.Read();

        }

 

        static void test(StringBuilder sb)

        {

            sb = new StringBuilder("2");

        }

复制代码错误的观念: 程序输出"2",因为StringBuilder是引用类型,函数内部sb变量重新指向了托管堆中的新对象,函数返回后,外部的sb变量也指向了这个新对象,因为是引用类型吗,我传的是引用。

在错误的观念中,认为 “ref引用传参” 仅对.net中的另一种基本类型--值类型有用。

  这种错误观念通常源于这样的经验,看代码2:


static void Main(string[] args)

        {          

            StringBuilder sb = new StringBuilder("1");

            test(sb);

            Console.WriteLine(sb.ToString());

            Console.Read();

        }

 

        static void test(StringBuilder sb)

        {

            sb.Append("2");

        }

复制代码
我们通常会很自豪的说:“看吧,程序输出12,这就是引用类型的特点,如果换成值类型就不是了!”。我们得出的结论并没有错,实际上,这正是引用类型的特点!然而将这个观念扩大到代码1的情况,就错了!
正确的理解:程序正确的输出是“1”,并没有因为StringBuilder是引用类型,就应该输出“2” 。如果要输出“2”,需要加ref:

       static void Main(string[] args)

        {          

            StringBuilder sb = new StringBuilder("1");

            test(ref sb);

            Console.WriteLine(sb.ToString());

            Console.Read();

        }

 

        static void test(ref StringBuilder sb)

        {

            sb = new StringBuilder("2");

        }

复制代码


对于ref传参,只要记住一点:对于值类型来说传的是值的地址,对于引用类型来说传的是地址的地址。

对于引用类型,同样记住一点:引用类型本身的地址是一个值类型。就像我们学习c时,指针本身的地址就是一个int。

好吧,用c来理解c#果然有点拗! 直观的理解:引用类型对象本身不改变,只改变对象的属性时,我们在操作同一个对象;如果连对象本身都可能会改变,就用ref传引用类型的对象吧!

为什么不用strng作测试呢?
因为string对象虽然是引用类型,但不能改变对象的属性CharArray,每次返回的都是新对象(看起来像值类型,其实不是!)。

 

结论: 给张图吧

posted on 2012-09-13 16:36  RJ  阅读(...)  评论(... 编辑 收藏

导航

统计