您的位置:知识库 » .NET技术

深入剖析引用参数Ref和Out

作者: Wu.Country@侠缘  来源: 博客园  发布时间: 2009-02-27 13:58  阅读: 4354 次  推荐: 0   原文链接   [收藏]  
摘要:Ref和Out 解释
[1] 深入剖析引用参数Ref和Out
[2] 深入剖析引用参数Ref和Out
但如果我们强行加上Ref或者Out关键字,会是什么结果呢???
1、如果是用Ref,那么结果是和什么都没用一样!即默认就是用的Ref。(让我们少打了几个字符)
2、如果是用Out,那么要遵守上面的3,4原则,即:在调用前,不必初始化引用对象,再简单一点:就是可以不用New一个对象。但在函数内,返回前一定要New一个,并且在New之前,参数对象是不能使用的。
也就是上面说到的,Out只是在调用前分配了一个地点,在调用函数中使用该地点。注意:这里“地点”一词决不是内存地址。

再思考一个问题:如果在使用Out参考时,在调用函数前,我们已经New了一个对象,再来调用函数结果会是什么呢?
你将“丢失”一部份内存(如果在C/C++里,一定是这样的)。也就是说,在调用了函数后,函数里New的一个对象会让函数外的对象丢失,而新的对象在函数内有效,在函数外也有效。幸运的是:原来的对象的内存并不会像C/C++那样完全的丢失,它将由垃圾回收器来管理了。所以我们并不担心内存的真正丢失问题(这真是一件值得庆幸的事)。

看这样的例子:

    class Class1
    
{
        
/// 
        
/// The main entry point for the application.
        
/// 

        [STAThread]
        
static void Main(string[] args) 
        
{
            TempClass m_class1    
= new TempClass();
            m_class1.m_member    
= 0;
            Console.WriteLine(
"i_obj data before changeData3 :{0}",m_class1.m_member);
            ChangeData3(
out m_class1);
            Console.WriteLine(
"i_obj data after changeData3 :{0}",m_class1.m_member);

        }

        
static void ChangeData3(out TempClass i_obj)
        
{
            i_obj    
= new TempClass();
            i_obj.m_member    
= 3;
//            Console.WriteLine("i_obj data in ChangeData3:{0}",i_obj.m_member);
        }

    }


    
class TempClass
    
{
        
public int m_member;
    }


到此为止,或许你已经觉得你已经对Ref和Out已经十分的了解了,然而你可能无法回答下面的一个问题:它的输出是什么?

    class Class1
    
{
        
/// 
        
/// The main entry point for the application.
        
/// 

        [STAThread]
        
static void Main(string[] args) 
        
{
            TempClass m_class1    
= new TempClass();
            m_class1.m_member    
= 0;
            TempClass m_class2    
= m_class1;
            ChangeData4(
ref m_class2,m_class2);
            Console.WriteLine(
"m_class1:{0},m_class2:{1}",m_class1.m_member,m_class2.m_member);
        }

        
static void ChangeData4(ref TempClass i_obj1,TempClass i_obj2)
        
{
            i_obj1    
= new TempClass();
            i_obj1.m_member    
= 41;
            i_obj2    
= new TempClass();
            i_obj2.m_member    
= 42;
        }

    }


    
class TempClass
    
{
        
public int m_member;
    }


请不要猜测它的结果,这样可能会让你犯一个错误。如果你利用前面的知识来理解,认为两个对象输出的结果是同一个对象的结果,那么你这回又是错误的!
这什么呢?前面不是说的很清楚吗?上面的函数参数一个用了ref,一个没有用,默认的都是Ref,也就是说:两个参数其实是一样的!!而且函数内用了两次New,因此,对象Class1的最后一个有效实例是最后一次New的结果,也就是说:class1和class2都将引用到(指向)函数内最后一次New的实例,所以最后输出应该都是42.

然而很不幸,这回结果是:m_class1:0,m_class2:41
而且它们的内存关系也是有点复杂的。让我们先来看看函数调用前的假想内存情况:

Class1->直接指向TempClass实例1

Class2->指向Class1,间接指向TempClass实例1

 

TempClass实例1,成员值:0

 

 

 

 

调用函数后的结果: 

Class1->直接指向TempClass实例1

Class2->直接指向TempClass实例2,因为第一个参数用的是Ref

 

TempClass实例1,成员值:0

TempClass实例2,第一次New的结果,成员值:41

TempClass实例3,第二次New的结果,但这只是在函数内的一个副本,该副本不能影响到函数外,即出了函数体就丢失,成员值:42

 

 

这就是为什么 会有两个结果了!!!也就是说:当我们用Ref来传递引用类型数据的一个引用时(这里的Class2就是这样的情况,它是一个指向TempClass实例1的一个引用),其实是使用的实例的一个副本。即:产生了即没有用Ref也没有用Out的效果。

[Post之后的修改]
这里请一定注意这里的调用:  ChangeData4(ref
 m_class2,m_class2);
读者自己试着这样试试:
  ChangeData4(ref
 m_class1,m_class2);
  ChangeData4(ref
 m_class2,m_class1);
  ChangeData4(ref
 m_class2,m_class1);
然后再分析一下内存,可能会有很大的收获。

最后一个问题:就是上面这种情况应用于值类型数据的时候会是什么情况呢?这就交给读者自己去解决了。

好了,最后一个引用的例子值得思考一下。希望对读者有帮助。

[第1页][第2页]
0
0
标签:CLR

.NET技术热门文章

    .NET技术最新文章

      最新新闻

        热门新闻