1. ref vs out

  1. out 和 ref生成的方法元数据基本没有差别,所以其对于CLR 和 IL没有差别。
  2. out 和 ref影响的是c#编译器的行为,它会对out和ref代码使用不同的检测规则

为尺寸较大的值类型使用out,可以提升代码的执行效率,因为避免了在方法调用时复制值类型的一个新实例

out/ref 初始化 作用域 返回
out 在调用函数中无需初始化 被调函数中无法访问初始值 被调函数返回前必须向out参数写入值
ref 需要初始化 读写 读写

2. ref 和out的作用到底是什么?

在Main函数中定义了一个变量(值类型或引用类型),ref或out参数传递时,传递的是 指向这个变量 栈中地址一个指针

  1. 对值类型,赋值修改,则修改内存桟中的值。
  2. 对引用类型,赋值一个新对象,则栈中指针指向新的 堆对象。

博客园 - C#程序员请不要混淆引用类型和ref引用传参

注意其中的注释和输出

ref vs not-ref

static void Main(string[] args)
{
    StringBuilder sb = new StringBuilder("1");
    
    // ================================================================
    // 未使用ref时,传递引用参数时,是在  栈中  新建了一个  堆对象  的引用
    //test(sb);
    //&sb
    //0x0617eec4
    //    sb: 0x02a2116c
    //&sb
    //0x0617ee74 //栈中的新指针实例
    //    sb: 0x02a2116c
    //&sb
    //0x0617ee74
    //    sb: 0x02a41904
    //&sb
    //0x0617eec4
    //    sb: 0x02a2116c
    //Console.WriteLine(sb.ToString());
    // out: 1

    // ================================================================
    // 使用ref是,传递引用参数时,传递的是指针的指针,并没有在栈中新建  指向 堆对象 的指针实例
    //test(ref sb);
    //&sb
    //0x0589ed74
    //    sb: 0x02ba116c
    //&sb
    //0x0589ed74 //指针的指针
    //    sb: 0x02ba116c
    //&sb
    //0x0589ed74
    //    sb: 0x02bc1904
    //&sb
    //0x0589ed74
    //    sb: 0x02bc1904
    //Console.WriteLine(sb.ToString());
    // out: 2

    // ==============================================================
    var str = "1";
    test(ref str);
    Console.WriteLine(str);
    // out: 2

    Console.Read();
}

static void test(ref StringBuilder sb)
{
    sb = new StringBuilder("2");
}

static void test(StringBuilder sb)
{
    sb = new StringBuilder("2");
}

static void test(ref string sb)
{
    sb = "2";
}

static void test(string sb)
{
    sb = "2";
}