C# ref和out关键

    今天在看一段C#代码的时候,发现对ref和out两个关键不了解,所以就查阅了C#语言相关的教程,深入的学习了一下。

ref关键字的作用是使参数按引用类型传递,这样控制权传递给调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。

 这里提到了引用类型,其实在C#中共有两种类型,一种是值类型(结构体、数值类型、bool型、枚举、可空类型),另一种是引用类型(自定义类、接口、委托、数组、字符串类型、object)。值类型和引用类型的区别在于以下几点:

1、值类型直接存储其值,变量本身就包含了实例数据,而引用类型保存的只是实例数据的内存引用。因此,一个值类型变量就永远不会影响到其他的值类型变量,而两个引用类型变量则很有可能指向同一地址,从而发生相互影响。

2、从内存分配上来看,值类型通常分配在线程的堆栈上,作用域结束时,所占空间自行释放,效率高,无需进行地址转换,而引用类型通常分配在托管堆上,由GC来控制其回收,需要进行地址转换,效率降低,这也正是c#需要定义两种数据类型的原因之一。

3、值类型均隐式派生自System.ValueType,而System.ValueType又直接派生于 System.Object,每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值,注意所有的值类型都是密封(sealed)的,所以无法派生 出新的值类型。而且System.ValueType本身是一个类类型,而不是值类型,因为它重写了object的Equals()方法,所以对值类型将 按照实例的值来比较,而不是比较引用地址。

4、C# 的统一类型系统,使得值类型可以转化为对象来处理,这就是常说的装箱和拆箱。由于装拆箱需要装建全新对象或做强制类型转换,这些操作所需时间和运算要远远大于赋值操作,因此不提倡使用它,同时也要尽量避免隐式装拆箱的发生。

注:栈是操作系统分配的一个连续的内存区域,用于快速访问数据。因为值类型的容量是已知的,因此它可存储在栈上。而托管堆是CLR在应用程序启动时为应用程序预留的一块连续内存区,是用于动态内存分配的内存区,引用类型的容量只有到运行时才能确定,所有用堆来存储引用类型。

理解了C#中值类型与引用类型的区别再来看ref关键字就会非常简单了。下面通过一个小例子来说明ref关键字的作用。

下面这段代码的功能是实现两个整数按由小到大的顺序进行排序。

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

namespace ref1
{
    class Program
    {

        /// <summary>
        
/// 从小到大进行排序
        
/// </summary>
        
/// <param name="a"></param>
        
/// <param name="b"></param>
        public static void sawp(int a, int b)
        {
            int c = 0;
            if (a > b)
            {
                c = a;
                a = b;
                b = c;
            }
            Console.WriteLine("a的值为:{0},b的值为:{1}", a, b);
        }

static void Main(string[] args)
        {
            int x = 6;
            int y = 4;
            sawp(x, y);
            Console.WriteLine("x的值为:{0},y的值为:{1}", x, y);
            Console.ReadLine();           
        }
    }
}

运行结果如下:

程序运行的结果出人预料,仔细分析后就会发现,swap函数的参数是通过值传递的,它只是将x、y的副本值进行了交换,而内存中的值是没有改变的。现在我们在参数的前面加上ref关键字。

View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ref1
{
    class Program
    {

        /// <summary>
        
/// 从小到大进行排序
        
/// </summary>
        
/// <param name="a"></param>
        
/// <param name="b"></param>
        public static void sawp(ref int a,ref int b)
        {
            int c = 0;
            if (a > b)
            {
                c = a;
                a = b;
                b = c;
            }
        }

 static void Main(string[] args)
        {
            int x = 6;
            int y = 4;
            sawp(ref x,ref y);
            Console.WriteLine("x的值为:{0},y的值为:{1}", x, y);
            Console.ReadLine();
        }
    }

 运行结果如下:

可以看到,程序给出了正确的结果。

下面来说说out关键字,out关键字的功能跟ref关键字的功能很相似,out关键字的作用是导致参数通过应用来传递。它们的区别就是ref关键要求变量必须在传递之前进行初始化,而out不需要。

下面通过一个小例子来学习一下out关键字。

View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ref1
{
    class Program
    {
       static int MaxIndex(int[] m_Array, out int m_Index)
        {
            m_Index = 0;
            int m_Max = m_Array[0];
            for (int i = 0; i < m_Array.Length; i++)
            {
                if (m_Array[i] > m_Max)
                {
                    m_Max = m_Array[i];
                    m_Index = i;
                }
            }
            return m_Max;
        }
        static void Main(string[] args)
        {
            int[] Array = new int[5] { 1222554411 };
            int maxIndex;//使用out关键字,此处不用初始化
            Console.WriteLine("数组中最大的值是:{0}", MaxIndex(Array, out maxIndex));
            Console.WriteLine("最大数的索引号是:{0}", maxIndex + 1);
            Console.ReadLine();
        }
    }
}

 运行结果如下:

  其实上面的程序也可以使用ref关键字来写:

View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ref1
{
    class Program
    {

        /// <summary>
        
/// 返回数组的最大值及最大值的索引值
        
/// </summary>
        
/// <param name="m_Array">数组</param>
        
/// <param name="m_Index">最大值的索引值</param>
        
/// <returns>数组中的最大值</returns>
        static int MaxIndex(int[] m_Array, ref int m_Index)
        {
            m_Index = 0;
            int m_Max = m_Array[0];
            for (int i = 0; i < m_Array.Length; i++)
            {
                if (m_Array[i] > m_Max)
                {
                    m_Max = m_Array[i];
                    m_Index = i;
                }
            }
            return m_Max;
        }
        static void Main(string[] args)
        {
            int[] Array = new int[5] { 1222554411 };
            int maxIndex=0;//使用ref关键字,此处需要初始化
            Console.WriteLine("数组中最大的值是:{0}", MaxIndex(Array, ref maxIndex));
            Console.WriteLine("最大数的索引号是:{0}", maxIndex + 1);
            Console.ReadLine();
        }
    }
}

 运行结果如下:

 

 

posted @ 2012-02-10 16:57  苍马之子  阅读(468)  评论(0编辑  收藏  举报