' ref'的内部工作带有指向同一地址的两个对象的关键字

时间:2012-06-07 00:00:41

标签: c# ref

查看下面的代码并告诉我为什么在调用函数UpdateContext之后,变量connection2没有与变量connection1相同的哈希码。

当我将变量connection2设置为connection1时,两个变量都有一个指向相同内存地址的指针。但是在函数UpdateContext中通过ref传递变量connection1后,使用'new'指令修改指针,connection1有一个新的指针地址,但connection2仍然是旧地址。

   class Program
   {
      static void Main(string[] args)
      {
         var connectionInitializer = new ConnectionInitializer();

         connectionInitializer.Initialize();

         Console.ReadLine();
      }
   }

   public class Connection
   {

   }

   public class ConnectionInitializer
   {
      public void Initialize()
      {
         var connection1 = new Connection();
         var connection2 = connection1;

         Console.WriteLine("Connection 1 (Before ref): " + connection1.GetHashCode());
         Console.WriteLine("Connection 2 (Before ref): " + connection2.GetHashCode());

         this.UpdateContext(ref connection1);

         Console.WriteLine("Connection 1 (After ref): " + connection1.GetHashCode());
         Console.WriteLine("Connection 2 (After ref): " + connection2.GetHashCode());
      }

      private void UpdateContext(ref Connection connection)
      {
         connection = new Connection();
      }
   }

感谢您的帮助。

5 个答案:

答案 0 :(得分:8)

您似乎误解了ref打算实现的目标。基本上,当您将变量作为ref参数传递时,它允许被调用者修改(原始)变量的值,就像它是本地的一样。鉴于此,为什么您希望覆盖变量connection1的值以更改分配给connection2的值?

换句话说,使用ref类似于此代码:

var connection1 = new Connection();
var connection2 = connection1;
connection1 = new Connection()

显然,在这种情况下,connection2应保持不变。你的情况也是如此。

答案 1 :(得分:3)

connection2仍引用原始Connection对象。已修改connection1以引用新的Connection对象。 connection1connection2不是字面上相同的参考。 connection2connection1的副本,这些引用在一段时间内都引用了同一个对象。

除了他们所指的内容之外,这两个引用没有任何有意义的联系,一个只是另一个引用的副本。更改原件不会反映在副本上。

答案 2 :(得分:1)

虽然Kirk Woll的回答是正确的,但我认为当他说你误解了ref关键字时,他错过了一点。这种误解很常见,但更多的是对参考类型本身的性质的误解。

Kirk的解释(“使用ref类似于此代码”)实际上反映了我记得的其他SO问题,例如“为什么以下示例不打印Goodbye?”

string a = "Hello";
string b = a;
a = "Goodbye";
Console.WriteLine(b);

(抱歉,找不到实际问题的链接。)

如果你记得引用类型变量存储引用引用类型的实例,那么跟踪更容易,而值类型变量直接存储一个实例价值类型。

我发现这比通常的“引用类型通过引用传递更好的思维方式;值类型通过值传递。”实际上,引用类型变量(缺少refout)通过值传递,但值本身是引用。这令人困惑。更不用说了:“引用类型变量包含对类型实例的引用”。

当然,ref关键字会使这一点复杂化,因为ref参数包含对变量的引用。这意味着引用类型ref参数存储对该类型实例的引用的引用。同样,如果您认为引用类型变量包含引用这一事实,您可以停止在引用变量的引用的ref参数。这比“参考......的参考”更容易推理。

答案 3 :(得分:0)

初始化连接对象时,它会分配新的内存,从而分配新的哈希码

答案 4 :(得分:0)

如果你说c ++,refs和outs实际上只是指针,你传递的是传递的标识符的地址。比较:

void foo(int** p);

int main()
{
  int* one = new int(4);
  int* two = one;

  cout << "one|two before: " << *one << "|" << *two << endl;

  foo(&one);

  cout << "one|two after: " << *one << "|" << *two << endl;

  return 0;
}

void foo(int** p)
{
  *p = new int(5);
}

输出:

one|two before: 4|4
one|two after: 5|4

注意我本可以使用c ++ ref传递,但在引擎盖下,这些只是指针。