我仍然对通过参考文件感到困惑。
如果我有一个Cache对象,我想访问/可用于许多对象,我使用构造函数注入注入它。我希望它影响我创建的单个缓存对象。例如
public class Cache {
public void Remove(string fileToRemove) {
...
}
}
public class ObjectLoader {
private Cache _Cache;
public ObjectLoader(Cache cache) {
}
public RemoveFromCacheFIleThatHasBeenDeletedOrSimilarOperation(string filename) {
_Cache.Remove(fileName);
}
}
当我将Cache传递给ObjectLoader构造函数时,我应该使用ref吗?
答案 0 :(得分:11)
在这种情况下,您不需要使用ref关键字。
Cache是一个类,它是一个引用类型。将引用传递给方法时,引用的副本(不是对象本身)将放入您的参数中。方法的内部和外部引用都指向堆上的同一个对象,使用一个对象的字段的修改将反映在另一个中。
在方法调用中添加ref会传入原始引用。这对于您将在调用方法中重新分配(即通过调用new
)引用指向的位置的情况非常有用。
答案 1 :(得分:7)
当您需要修改引用指向的内容时,请使用'ref'关键字。将引用类型传递给方法时, 按值传递,但该值是该引用的副本,它将传递给方法。这意味着您可以更改引用对象的常规状态(即属性/字段),但如果您尝试更改对您的引用点的影响,则只会影响副本。
例如,给定此方法......
private void Foo( MyClass obj )
{
obj = new MyClass( );
obj.SomeProperty = true;
}
我们可以传递参数,然后查看它是否受到影响:
MyClass test = new MyClass( );
test.SomeProperty = false;
Foo( test );
Console.WriteLine( test.SomeProperty ); // prints "False"
现在,如果我们使用'ref'关键字定义方法......
private void Foo( ref MyClass obj )
{
obj = new MyClass( );
obj.SomeProperty = true;
}
输出将为“True”,因为实际引用已传递给方法,而不是副本。我们更改了该参考指向函数内部的内容,并且我们看到了这些更改的影响。
当您省略'ref'关键字时,您只是在堆上创建一个指向对象的新指针。如果更改一个指针,则不会更改另一个指针。
...
所以,回答你的问题;不,您不需要使用'ref'关键字来更改单个Cache对象传递给方法时的状态。
答案 2 :(得分:1)
我想你想知道会创建多少Cache
个对象的副本。您只希望多个客户端对象共享一个副本。好吧,只要您想知道将创建多少单独的对象副本,就可以在C#中记住一条非常简单的规则。
如果声明了对象的类型
class
关键字,然后有 只有一种方法来制作新的实例 它:使用new
关键字。
这有一些小的例外:您可以调用创建对象的BCL方法,但关键是它是显式的。你必须特别要求它发生。该语言不会自动复制class
个对象。
因此,在您的示例中,您有一个名为class
的{{1}},因此您肯定知道您可以根据需要传递Cache
类型的变量,并且不会将创建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
构造函数的两次调用。每次调用ObjectLoader
的构造函数时,我们都会传递它ObjectLoader
。我们必须放置c
关键字,这是一件非常好的事情,因为它让阅读代码的人知道发生了奇怪的事情。变量ref
在c
的构造函数返回后指向不同的Cache
。因此ObjectLoader
的{{1}}最终会存储指向不同b
到ObjectLoader
的指针!
毋庸置疑,对于代码来说,这将是一个非常混乱的模式。如果我们不必将Cache
关键字放在呼叫站点上,那就更糟了!
答案 3 :(得分:-3)
即使在.NET框架中声明它们通过函数参数中的值传递,对象也会通过引用自动传递。
这是因为对象本身是引用类型,因此您可以修改对象的成员,即使您无法替换对象本身。
见
http://msdn.microsoft.com/en-us/library/aa903253(VS.71).aspx