C#基础-ref、out

1.默认状况下,C#假定全部的方法参数传递都是传值的。函数

以下面的方法:spa

public static void Main(string[] args)
 {
     int val = 5;

     //调用AddValue方法,aVal会从新拷贝一份val的值(即aVal为val的一个实例副本),方法内部的操做并不会改变val的值。
     AddValue(val);

     //val值仍是5,并无加1
     Console.WriteLine(val);
     Console.ReadLine();
 }

 public static void AddValue(int aVal)
 {
     aVal = aVal + 1;
 }
 
若是指望在调用AddValue方法之后,val加一,有两种方案:
一、修改AddValue,将修改后的值做为返回值,并赋值给val。
二、使用ref关键字、out关键字。传入参数时,再也不传入一个原来类型的拷贝,而是直接传入原有值类型的地址(相似于引用类型) ,这样在方法内部的任意修改都会影响到传入的值类型。
 
2.引用类型的ref、out
引用类型做为方法参数传入时,对象的引用(或者指向该对象的指针)会传入方法参数,在方法内部对该对象的修改,被调用者也能直接看到。
这样是否是就不须要ref、out关键字了呢?
eg:
其实,引用类型做为方法参数传入时,理论上仍是会新建一个变量,该变量指向和原有引用类型的指向相同。
 
若是在调用方法内部修改了引用类型的属性,使用ref和不使用ref没有区别,参考代码为:
public static void Main(string[] args)
{
    User user = new User(); user.Name = "Lisa";

    //不使用关键字ref,在调用方法内部修改User对象的属性,也会影响传入参数User.
    //由于此时的User和方法参数aUser都指向同一份引用。
    ChangeUser(user);
    Console.WriteLine(user.Name);

    //使用关键字ref,在调用方法内部修改User对象的属性,也会影响传入参数User
    //由于此时的User和方法参数aUser是同一个对象。
    ChangeUser(ref user);
    Console.WriteLine(user.Name);

    Console.ReadLine();
}

public static void ChangeUser(User aUser)
{
    aUser.Name = "Alan1";
}

public static void ChangeUser(ref User aUser)
{
    aUser.Name = "Alan2";
}
输出结果为:
Alan1
Alan2
此时看不出不使用ref和使用ref的区别,一样对在方法内部修改User的Name属性,效果同样
 
 
若是在调用方法内部修改了引用类型的指向,使用ref和不使用ref有区别,参考代码为:
public static void Main(string[] args)
{
    User user = new User();

    //不使用关键字ref,在调用方法内部修改User对象的引用,不会影响传入参数User.
    //由于在栈中有两个独立的指针user、aUser
    ChangeUser(user);
    if (user != null)
    {
        Console.WriteLine("user1 is not null");
    }
    else
    {
        Console.WriteLine("user1 is null");
    }

    //使用关键字ref,在调用方法内部修改User对象的引用,会影响传入参数User.
    //由于在栈中仅有一个指针user
    ChangeUser(ref user);
    if (user != null)
    {
        Console.WriteLine("user2 is not null");
    }
    else
    {
        Console.WriteLine("user2 is null");
    }

    Console.ReadLine();
}

public static void ChangeUser(User aUser)
{
    aUser = null;
}

public static void ChangeUser(ref User aUser)
{
    aUser = null;
}
输出结果为:
user1 is not null
user2 is null
此时可以明细看错不使用ref和使用ref的区别,一样对在方法内部赋值User ==null,效果不同
 
引用关系图为:
引用类型Val自己
image 
 
调用Change(aVal)方法之后:
image
 
调用Change(ref aVal)方法之后:
image 
从上可知,若是须要真正的指向同一个引用,在方法内部的任何改变都会影响到传入参数,仍是须要使用ref和out关键字。
 
3.从CLR来讲,ref和out自己是同样的,都致使传递指向实例的指针。
惟一的区别是:
ref参数须要调用者在调用方法以前初始化参数的值(强制要求,不赋值编译不经过)
out参数不期望调用者在调用方法以前初始化参数默认值,即便调用者以前赋值,在调用方法内部也会从新赋值(即调用者的赋值会被替换,赋值无效,因此不建议调用者提早赋值)。
 
4.其它
a.容许对方法进行ref和out进行重载(即认为使用ref/out跟不使用ref/out函数签名不一致)
如下方法可以编译经过。

public static void ChangeUser(User aUser)
{
    aUser = null;
} .net

public static void ChangeUser(ref User aUser)
{
    aUser = null;
} 指针

编译经过code

可是,若是两个方法只有ref和out的区别,是不容许的。由于两个方法签名的元数据是彻底相同的。
如下方法编译不过

public static void ChangeUser(ref User aUser)
{
    aUser = null;
} 对象

public static void ChangeUser(out User aUser)
{
    aUser = null;
} blog

编译不过: get

错误: “ChangeUser”不能定义仅在 ref 和 out 上有差异的重载方法   string

b.使用ref/out关键字时,方法定义和调用时参数类型必须一致。 it

相关文章
相关标签/搜索