C# 引用类型和引用之间的差异
我正在阅读Eric Lippert的以下博客: 在这篇文章中,他提到开场白中有三种价值观:C# 引用类型和引用之间的差异,c#,.net,clr,C#,.net,Clr,我正在阅读Eric Lippert的以下博客: 在这篇文章中,他提到开场白中有三种价值观: 值类型的实例 引用类型的实例 参考资料 这是不完整的。推荐信呢?引用既不是值类型,也不是引用类型的实例,而是值 因此,在以下示例中: int i = 10; string s = "Hello" 第一个是值类型的实例,第二个是引用类型的实例。那么,第三种类型是什么,引用以及我们如何获得它呢?引用类型的字段和变量,例如s,是对堆上引用类型实例的引用 您从不直接使用引用类型的实例;相反,您通过引用来使用它
int i = 10;
string s = "Hello"
第一个是值类型的实例,第二个是引用类型的实例。那么,第三种类型是什么,引用以及我们如何获得它呢?引用类型的字段和变量,例如
s
,是对堆上引用类型实例的引用
您从不直接使用引用类型的实例;相反,您通过引用来使用它
那么,第三种类型是什么,引用,我们如何获得它
变量s
是一个保存引用值的变量。此值是对内存中字符串的引用(值为“Hello”
)
为了更清楚地说明这一点,假设您有:
string s1 = "Hello";
string s2 = s1;
在这种情况下,
s1
和s2
都是变量,每个变量都是对同一引用类型实例(字符串)的引用。这里只涉及一个实际的字符串实例(引用类型),但有两个对该实例的引用。引用实际上不是“第三种类型”。它实际上是一个指针,指向一个对象的具体实例。看看这个例子:
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中,该实例的值被覆盖。
最后一个示例是MyClass的对象。所有类都是引用类型,这就是为什么您总是将它们作为引用传递(不需要特殊的关键字)
您可以将引用视为计算机内存中的地址。位于该地址的字节构成对象。如果您将其作为值传递,则将该字节取出并传递给函数。如果将其作为引用传递,则只传递地址。而在被调用的函数中,您可以从该地址读取字节或写入该地址。每次更改都会影响调用函数变量,因为它们指向计算机内存中完全相同的字节这不完全是.Net中发生的事情(它在虚拟机中运行),但我认为这个类比将帮助您理解这个概念
我们为什么要使用参考资料?原因有很多。其中之一是,按值传递大对象的速度非常慢,需要对其进行克隆。当您传递一个对象的引用时,不管该对象有多大,您只传递内存中包含其“地址”的几个字节
此外,对象可能包含无法克隆的元素(如打开的套接字)。使用引用,您可以轻松地在函数之间传递这样的对象
还值得一提的是,scstruct,尽管它们看起来非常类似于类,但实际上是值类型,并且表现为值类型(当您将结构传递给函数时,实际上是传递了一个克隆-一个新实例)。@marcGravel,Eric Lippert的
s
是一个变量,而不是链接中的引用:“引用既不是值类型,也不是引用类型的实例,而是值。”。“@NewHire,而这正是他们普遍存在的地方。因此,虽然从语言规范来看这不是必要的,但它在事实上仍然是准确的。@用户确实,说“s的值”更合适。@NewHire:理论上,CLR可以在堆栈上分配引用类型的引用对象,但在实践中,这种情况从未发生过。但是,根据保存引用的变量的生存期,可以在堆栈或堆上分配引用。参考文献是数据,它们必须生活在某个地方。