C#值类型、引用类型及ref/out的使用

1.值类型

C#的所有值类型均隐式派生自System.ValueType:

结构体:struct(直接派生于System.ValueType);

数值类型:

整型:sbyte(System.SByte的别名),short(System.Int16),int(System.Int32),long(System.Int64),byte(System.Byte),ushort(System.UInt16),uint(System.UInt32),ulong(System.UInt64),char(System.Char);

浮点型:float(System.Single),double(System.Double);

用于财务计算的高精度decimal型:decimal(System.Decimal);

bool型:bool(System.Boolean的别名);

用户定义的结构体(派生于System.ValueType);

枚举:enum(派生于System.Enum);

可空类型(派生于System.Nullable<T>泛型结构体,T?实际上是System.Nullable<T>的别名)。

可以用Type.IsValueType属性来判断一个类型是否为值类型:

TestType testType = new TestType ();
  if (testTypetype.GetType().IsValueType)
  {
     Console.WriteLine("{0} is value type.", testType.ToString());
  }

2.引用类型

C#有以下一些引用类型:

数组(派生于System.Array)

用户用定义的以下类型:

类:class(派生于System.Object);

接口:interface(接口不是一个“东西”,所以不存在派生于何处的问题。Anders在《C# Programming Language》中说,接口只是表示一种约定[contract]);

委托:delegate(派生于System.Delegate)。

object(System.Object的别名);

字符串:string(System.String的别名)。


引用类型和值类型都继承自System.Object类。不同的是,几乎所有的引用类型都直接从System.Object继承,而值类型则继承其子类,即 直接继承System.ValueType。System.ValueType直接派生于System.Object。即System.ValueType本身是一个类类型,而不是值类型。其关键在于ValueType重写了Equals()方法,从而对值类型按照实例的值来比较,而不是引用地址来比较。

值类型变量声明后,不管是否已经赋值,编译器为其分配内存。
引用类型当声明一个类时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间。当使用 new 创建一个类的实例时,分配堆上的空间,并把堆上空间的地址保存到栈上分配的小片空间中。
值类型的实例通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中。

引用类型的对象总是在进程堆中分配(动态分配)。

可以看出:

引用类型与值类型相同的是,结构体也可以实现接口;
引用类型可以派生出新的类型,而值类型不能;
引用类型可以包含null值,值类型不能(可空类型功能允许将 null 赋给值类型);

引用类型变量的赋值只复制对对象的引用,而不复制对象本身。而将一个值类型变量赋给另一个值类型变量时,将复制包含的值。

ref和out

通过上面的讲述我们可以知道,当值类型作为一个方法的参数时,在方法内参数的改变并不能使此值类型数据发生改变,这里也可以称为值传递。使用引用类型作为一个方法的参数时,在方法内参数的改变,会使此引用类型也改变,这里也可以称为引用传递。而ref和out的作用,就是使值传递变为引用传递。

ref和out的使用很简单,在方法的参数列表中要引用传递的参数的数据类型前加ref或out,在调用此方法时也要在这些参数前加ref或out,下面我们看看例子:

static void Main()
{ int a = 1, b = 2; Swop(a, b); Console.WriteLine("a"+a+"b"+b); Swop1(ref a,ref b); Console.WriteLine("a" + a + "b" + b); } static void Swop(int a,int b) { int c = a; a = b; b = c; } static void Swop1(ref int a,ref int b) { int c = a; a = b; b = c; }

输出结果:

a1b2

a2b1

从上面代码可以看出没加ref,是值传递,Main方法里的a和b并没有改变,而加了ref后,变成引用传递,Main方法里的a和b也改变了。

static void Main()
        {
            int a, b ;
            Swop2(out a,out b);
            Console.WriteLine("a" + a + "b" + b);
        }
        static void Swop2(out int a,out int b)
        {
            a = 1;
            b = 2;
        }

我们再来看out的使用,可以看出,out和ref还是有很大区别的,在实际使用中,它们的作用其实也各有不同。

区别和作用

1.使用ref的参数必须在传参之前初始化,而out可以在传参前不初始化。

2.out指定的参数在进入函数时会清空自己,必须在函数内部赋初值。而ref指定的参数不需要。

3.ref一般用于需要方法内部对参数的改变使外面的数据也改变的情况,而out一般用于需要多个返回值时,使用out定义参数去接收返回值.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值