代码改变世界

c#进阶-方法中的ref和out

2010-12-27 22:30  撞破南墙  阅读(2200)  评论(2编辑  收藏  举报

在一个方法中 你必须知道每个参数是引用类型还是值类型否则你将发现你无法控制程序。

这些细节并不是每个.NET程序员都需要知道,但是却是进阶必备的,差距也在于此。

 

在C#中默认是使用值类型,你可以使用REF 和OUT 来使之变成引用类型。

在CLR中只有1个bit去区分它们是ref还是out。如果使用的是out 那么

 

1你不能够在赋值前使用它,因为他还未赋值。

2在方法返回的时候你必须为他赋值

 

如果是ref  你可以直接读写他。

 

REF 和 OUT 都使得方法中的参数把值带回来,不同的在于编译器把对他们进行了检查,如下面的情况。

 

public sealed class Program { 
public static void Main() { 
Int32 x; 
// x is not initialized. 
// The following line fails to compile, producing 
// error CS0165: Use of unassigned local variable 'x'. 
AddVal(ref x); 
Console.WriteLine(x); 
}
private static void AddVal(ref Int32 v) { 
+= 10// This method can use the initialized value in v. 
}

 

 

 

在C#中为什么一定要申明是ref 还是 out ,如果不申明编译一样没有问题,在C++中就没有ref 和out这回事。

应该是C#的设计者认为开发者应该应该清楚的知道自己传递的参数的状态作用。

 

在c#中,允许以下的重载。

 

 

public sealed class Point { 
static void Add(Point p) { ... } 
static void Add(ref Point p) { ... } 
}

 

 

 

但是不允许同时使用 REF和OUT的重载。因为元数据表示两个方法的签名是一样的。

 

image

 

让两个引用类型的变量交换

 

public static void Swap(ref Object a, ref Object b) { 
Object t 
= b; 
= a; 
= t; 

//To swap references to two String objects, you’d probably
//think that you //could write code     like this:

public static void SomeMethod() { 
String s1 
= "Hello"
String s2 
= "World"
// Variables that are passed by reference 
// must match what the method expects. 
Object o1 = s1, o2 = s2; 
Swap(
ref o1, ref o2); 
// Now cast the objects back to strings. 
s1 = (String) o1; 
s2 
= (String) o2;
//
Console.WriteLine(s1); // Displays "World" 
Console.WriteLine(s2); // Displays "Hello" 
}

 

 

 

如果Swap(ref s1, ref s2); 似乎没有问题,但是

 

image 

对于ref 他是执行了类型检查的。