引用参数ref和out区别
这两个关键字的区别在于那个方法负责初始化引用对象,如果方法的参数标记为out,
那么调用者不希望在调用方法之前初始化对象,被调用的方法不能读取对象的值,而且被
调用的方法必须在返回之前为对象赋值。如果方法的参数标记为ref,那么调用者必须在
调用方法之前首先初始化参数的值,被调用的方法可以读取参数或者为参数赋值。
例2:
using System;
using System.IO;
public sealed class Program
{
public static void Main()
{
FileStream fs = null; //初始化为null (必要的操作)
//打开第一个待处理的文件
ProcessFiles(ref fs);
//如果有更多的需要处理的文件,则继续
for(; fs != null; ProcessFiles(ref fs))
{
//处理文件
fs.read();
}
}
private static void ProcessFiles(ref fs)
{
//如果先前的文件时打开的,则将其关闭
if(fs != null)
{
fs.close(); //关闭最后一个操作的文件
}
//打开下一个文件:如果没有文件,则返回null
if(noMoreFilesToProcess)
{
fs = null;
}
else
{
fs = new FileStream(...);
}
}
}
例3:如何利用ref关键字实现一个用于交换两个引用类型的方法:
public static void Swap(ref Object a, ref Object b)
{
Object t = b;
b = a;
a = t;
}
为了交换两个String对象的引用,看一下错误的代码:
public static void SomeMethod()
{
String s1 = "Jeffrey";
String s2 = "Kichter";
Swap(ref s1, ref s2);
Console.WriteLine(s1); //期望显示“Kichter”
Console.WriteLine(s2); //期望显示“Jeffrey”
}
但是,上述代码无法通过编译。问题在于按引用传递给方法的变量的类型必须与方法签名中
声明类型相同,换句话说,Swep希望有两个Object引用,而不是两个String应用。为了交换String
引用,需要向下面这样的代码:
public static void SomeMethod()
{
String s1 = "Jeffrey";
String s2 = "Richter";
//以引用方式传递的变量必须和方法期望的参数类型匹配
//将对象强制转换回字符串
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); //显示“Richter”
Console.WriteLine(s2); //显示“Jeffrey”
}
这个版本的SomeMethod可以通过编译, 并且如预期的一样执行。传递的参数必须与方法期望的参数相匹配,旨在确保类型安全
下面的代码(信号不会进行编译),显示了类型安全吃如何进行折中的:
internal sealed class SomeType
{
public Int32 m_val;
}
public sealed class Program
{
public static void Main()
{
SomeType st;
//下以行代码将产生错信息:error CS1503:参数‘1’:不能从‘ref SomeType’ 转换成‘ref objiect’
GetAnObject(out st);
Console.WriteLine(st.Mval);
}
private static void GetAnObject(out Object o)
{
o = new String('x',100);
}
}
前面代码中,Main显然希望GetAnObject方法返回一个SomeType对象。但是,因为GetAnObject的简明表示的是一个Object引用,
所以GetAnObject可以将o初始化某个类型的对象。在这个范例中,当GetAnObject返回Main时,st将引用String对象,这明显不是SomeType对象,
因此对Console.WriteLine的调用肯定会失败。幸亏c#编译器无法编译前面的代码,因为st是对SomeTypd
对象的引用,而GetAnObject要求的是Object对象引用。
可以用泛型(getneric)来修正这些方法,以便他们按照期望的方式运行,下面是前面示范的Swap方法的修正:
public static void Swap<T>(ref T a, ref T b)
{
T t = b;
b = a;
a = t;
}
这两个关键字的区别在于那个方法负责初始化引用对象,如果方法的参数标记为out,
那么调用者不希望在调用方法之前初始化对象,被调用的方法不能读取对象的值,而且被
调用的方法必须在返回之前为对象赋值。如果方法的参数标记为ref,那么调用者必须在
调用方法之前首先初始化参数的值,被调用的方法可以读取参数或者为参数赋值。
例2:
using System;
using System.IO;
public sealed class Program
{
public static void Main()
{
FileStream fs = null; //初始化为null (必要的操作)
//打开第一个待处理的文件
ProcessFiles(ref fs);
//如果有更多的需要处理的文件,则继续
for(; fs != null; ProcessFiles(ref fs))
{
//处理文件
fs.read();
}
}
private static void ProcessFiles(ref fs)
{
//如果先前的文件时打开的,则将其关闭
if(fs != null)
{
fs.close(); //关闭最后一个操作的文件
}
//打开下一个文件:如果没有文件,则返回null
if(noMoreFilesToProcess)
{
fs = null;
}
else
{
fs = new FileStream(...);
}
}
}
例3:如何利用ref关键字实现一个用于交换两个引用类型的方法:
public static void Swap(ref Object a, ref Object b)
{
Object t = b;
b = a;
a = t;
}
为了交换两个String对象的引用,看一下错误的代码:
public static void SomeMethod()
{
String s1 = "Jeffrey";
String s2 = "Kichter";
Swap(ref s1, ref s2);
Console.WriteLine(s1); //期望显示“Kichter”
Console.WriteLine(s2); //期望显示“Jeffrey”
}
但是,上述代码无法通过编译。问题在于按引用传递给方法的变量的类型必须与方法签名中
声明类型相同,换句话说,Swep希望有两个Object引用,而不是两个String应用。为了交换String
引用,需要向下面这样的代码:
public static void SomeMethod()
{
String s1 = "Jeffrey";
String s2 = "Richter";
//以引用方式传递的变量必须和方法期望的参数类型匹配
//将对象强制转换回字符串
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); //显示“Richter”
Console.WriteLine(s2); //显示“Jeffrey”
}
这个版本的SomeMethod可以通过编译, 并且如预期的一样执行。传递的参数必须与方法期望的参数相匹配,旨在确保类型安全
下面的代码(信号不会进行编译),显示了类型安全吃如何进行折中的:
internal sealed class SomeType
{
public Int32 m_val;
}
public sealed class Program
{
public static void Main()
{
SomeType st;
//下以行代码将产生错信息:error CS1503:参数‘1’:不能从‘ref SomeType’ 转换成‘ref objiect’
GetAnObject(out st);
Console.WriteLine(st.Mval);
}
private static void GetAnObject(out Object o)
{
o = new String('x',100);
}
}
前面代码中,Main显然希望GetAnObject方法返回一个SomeType对象。但是,因为GetAnObject的简明表示的是一个Object引用,
所以GetAnObject可以将o初始化某个类型的对象。在这个范例中,当GetAnObject返回Main时,st将引用String对象,这明显不是SomeType对象,
因此对Console.WriteLine的调用肯定会失败。幸亏c#编译器无法编译前面的代码,因为st是对SomeTypd
对象的引用,而GetAnObject要求的是Object对象引用。
可以用泛型(getneric)来修正这些方法,以便他们按照期望的方式运行,下面是前面示范的Swap方法的修正:
public static void Swap<T>(ref T a, ref T b)
{
T t = b;
b = a;
a = t;
}