参考类型和参考文献之间的区别

时间:2014-03-26 19:55:34

标签: c# .net clr

我正在阅读Eric Lippert的博客:The truth about Value types

在此,他提到开幕式中有三种价值观:

  1. 价值类型实例

  2. 参考类型实例

  3. 参考

      

    不完整。参考怎么样?引用既不是值类型也不是引用类型的实例,但它们是值..

  4. 因此,在以下示例中:

    int i = 10;
    string s = "Hello"
    

    首先是值类型的实例,第二个是引用类型的实例。那么,第三种类型是什么,参考文献以及我们如何获得它?

3 个答案:

答案 0 :(得分:4)

  

那么,第三种类型是什么,参考文献以及我们如何获得它?

变量s是一个保存引用值的变量。此值是对内存中字符串(值为"Hello")的引用。

为了使这一点更清楚,请说:

 string s1 = "Hello";
 string s2 = s1;

在这种情况下,s1s2都是变量,每个变量都是对同一引用类型实例(字符串)的引用。这里只涉及一个实际的字符串实例(引用类型),但是有两个对该实例的引用。

答案 1 :(得分:3)

引用类型的字段和变量(例如s)是对存在于堆上的引用类型实例的引用。

您永远不会直接使用引用类型的实例;相反,你通过参考使用它。

答案 2 :(得分:0)

参考不是真正的第三种类型'。它实际上是一个指向对象的具体实例的指针。看一下这个例子:

class MyClass
{
    public string Str { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        int a = 1;
        int b = 2;
        int c = 3;
        var myObj = new MyClass
        {
            Str = "Whatever"
        };

        Console.WriteLine("{0};\t{1};\t{2};\t{3}", a, b, c, myObj.Str);
        MyFunction(a, ref b, out c, myObj);
        Console.WriteLine("{0};\t{1};\t{2};\t{3}", a, b, c, myObj.Str);

        Console.ReadLine();
    }

    static void MyFunction(int justValue, ref int refInt, out int outInt, MyClass obj)
    {
        obj.Str = "Hello";
        justValue = 101;
        refInt = 102;
        outInt = 103; // similar to refInt, but you MUST set the value of the parameter if it's uses 'out' keyword
    }
}

该程序的输出是:

1;      2;      3;      Whatever
1;      102;    103;    Hello

专注于MyFunction:

我们传递的第一个参数是一个简单的int,它是一个值类型。默认情况下,值作为参数传递时克隆值类型(正在创建新实例)。这就是' a'没有改变。

您可以通过添加' ref'来更改此行为。或者' out'参数的关键字。在这种情况下,您实际上传递了对int的实例的引用。在MyFunction中,正在覆盖该实例的值。 Here you can read move out ref and out

最后一个例子是MyClass的对象。所有类都是引用类型,这就是为什么总是将它们作为引用传递(不需要特殊关键字)。

您可以考虑有关计算机内存中地址的引用。该地址的字节构成您的对象。如果将其作为值传递,则将该字节输出并将其传递给函数。如果您将其作为参考传递,则只传递地址。在被调用的函数中,您可以从该地址读取字节或写入该地址。每个更改都会影响调用函数变量,因为它们指向计算机内存中完全相同的字节。 它并不完全是.Net(它在虚拟机中运行)中发生的事情,但我认为这个类比将帮助您理解这个概念。

为什么我们使用引用?原因很多。其中之一是按值传递一个大对象会非常慢并且需要克隆它。当您传递对象的引用时,无论该对象有多大,您只需传递包含它的几个字节的地址'在记忆中。

此外,您的对象可能包含无法克隆的元素(如打开的套接字)。使用引用,您可以轻松地在函数之间传递这样的对象。

值得一提的是,即使它们看起来非常类似于类,它们实际上是值类型并且表现为值类型(当您将结构传递给函数时,实际上您传递了一个克隆 - 一个新实例)。