通过参考?

时间:2009-07-20 05:38:02

标签: c# .net

我仍然对通过参考文件感到困惑。

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

4 个答案:

答案 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关键字,这是一件非常好的事情,因为它让阅读代码的人知道发生了奇怪的事情。变量refc的构造函数返回后指向不同的Cache。因此ObjectLoader的{​​{1}}最终会存储指向不同bObjectLoader的指针!

毋庸置疑,对于代码来说,这将是一个非常混乱的模式。如果我们不必将Cache关键字放在呼叫站点上,那就更糟了!

答案 3 :(得分:-3)

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

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

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