• 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();
            }
        }
    }

     运行结果如下:

  • 相关阅读:
    D
    A
    D
    G
    H
    E
    F
    B
    D
    oracle中新建用户和赋予权限
  • 原文地址:https://www.cnblogs.com/shuai/p/2345668.html
Copyright © 2020-2023  润新知