我想您想知道将创建多少个Cache 对象的副本。您只希望一个副本由多个客户端对象共享。嗯,在 C# 中有一条非常简单的规则,您可以记住,只要您想知道将创建多少个单独的对象副本。
如果对象的类型被声明为
class 关键字,然后有
只有一种方法可以创建一个新的实例
它:使用 new 关键字。
对此有一些小例外:您可以调用创建对象的 BCL 方法,但关键是它是显式的。你必须特别要求它发生。该语言不会自动复制class 对象。
因此,在您的示例中,您有一个名为 Cache 的 class,因此您确定可以随意传递 Cache 类型的变量,并且没有更多 Cache 的副本将被创建。分配有该对象的所有变量都将“指向”同一个原始对象。这是因为Cache 变量不存储对象本身,而只存储Cache 对象在内存中的位置。
将此与声明 struct 类型而不是 class 的情况进行对比。现在,当您声明该类型的变量时,变量本身必须足够大以存储在struct 中声明的所有数据。每个变量都是一个单独的副本。每个参数都是一个单独的副本。
您可以通过添加 ref 关键字来覆盖它,但在大多数程序中它是一个非常不寻常的关键字。 out 关键字更常见,最好将其视为一种为方法提供多个返回值的方法。
ref 对class 类型的变量有什么影响?在您的示例中:
public ObjectLoader(Cache cache) {
// do stuff with cache (store it?)
}
我可以像这样构造两个对象加载器:
Cache c = new Cache();
ObjectLoader a = new ObjectLoader(c),
ObjectLoader b = new ObjectLoader(c);
我们刚刚创建了多少对象?只需计算new 关键字。现在,假设我们添加了 ref 关键字:
public ObjectLoader(ref Cache cache) {
_cache = cache; // store
// do something very odd!
cache = new Cache();
}
隐藏在该构造函数中,我创建了另一个缓存,并将其存储在我传递的参数中。因为是ref 参数,所以我影响了调用者的变量!所以在调用代码中:
Cache c = new Cache();
ObjectLoader a = new ObjectLoader(ref c),
ObjectLoader b = new ObjectLoader(ref c);
现在我们有五个new 的用法:三个在上面的sn-p 中,加上两个对修改后的ObjectLoader 构造函数的调用。每次调用ObjectLoader 的构造函数时,我们都会传递c。我们必须输入ref 关键字,这是一件非常好的事情,因为它让阅读代码的人知道发生了一些奇怪的事情。在ObjectLoader 的构造函数返回后,变量c 指向不同的Cache。所以b 的ObjectLoader 最终存储了一个指向不同Cache 到a 的指针!
不用说,对于代码来说,这将是一个相当混乱的模式。如果我们不必将ref 关键字放在调用站点上,那就更糟了!