C#框架阅读笔记--引用参数ref和out区别

来源:互联网 发布:淘宝五金冠店铺 编辑:程序博客网 时间:2024/06/01 14:59
引用参数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;
}


原创粉丝点击