通过参考?

我仍然对通过引用感到困惑。

如果我有一个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吗?

不,在这种情况下你不需要使用ref关键字。

Cache是​​一个类,它是一个引用类型。 将引用传递给方法时,引用的副本(不是对象本身)将放入您的参数中。 方法的内部和外部引用都指向堆上的同一对象,并且使用一个对象的字段的修改将反映在另一个中。

在方法调用中添加ref会传入原始引用。 这在您将在调用方法中重新分配(即通过调用new )引用指向的位置的情况下非常有用。

当您需要修改引用指向的内容时,请使用’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对象传递给方法时的状态。

我想你想知道会创建多少个Cache对象的副本。 您只希望多个客户端对象共享一个副本。 好吧,只要您想知道将创建多少单独的对象副本,就可以在C#中记住一个非常简单的规则。

如果使用class关键字声明对象的类型,那么只有一种方法可以创建它的新实例:使用new关键字。

这有一些小的例外:您可以调用创建对象的BCL方法,但关键是它是显式的。 你必须特别要求它发生。 该语言不会自动复制class对象。

因此,在您的示例中,您有一个名为Cacheclass ,因此您可以确切地知道可以根据需要传递Cache类型的变量,并且不会创建更多的Cache副本。 将该对象分配给它们的所有变量将“指向”同一原始对象。 这是因为Cache变量不存储对象本身,而只存储Cache对象在内存中的位置。

将此与您声明struct类型而不是class情况进行对比。 现在,当您声明该类型的变量时,变量本身必须足够大,以存储struct声明的所有数据。 每个变量都是一个单独的副本。 每个参数都是一个单独的副本。

您可以通过添加ref关键字来覆盖它,但在大多数程序中它是一个非常不寻常的关键字。 out关键字更常见,最好将其视为为方法提供多个返回值的方法。

如果变量属于class类型,那么ref对变量有什么影响? 在你的例子中:

 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的构造函数时,我们都会传递它。 我们必须放置ref关键字,这是一件非常好的事情,因为它让阅读代码的人知道发生了奇怪的事情。 在ObjectLoader的构造函数返回后,变量c指向不同的Cache 。 所以bObjectLoader最终将指向不同Cache的指针存储到a

毋庸置疑,对于代码而言,这将是一个非常混乱的模式。 如果我们不必将ref关键字放在调用站点,那就更糟了!

即使在.NET框架中声明它们通过函数参数中的值传递,对象也会通过引用自动传递。

这是因为对象本身是引用类型,因此您可以修改对象的成员,即使您无法替换对象本身。

看到

http://msdn.microsoft.com/en-us/library/aa903253(VS.71).aspx