“ref”关键字的内部工作,其中两个对象指向同一地址

本文关键字:对象 两个 地址 关键字 ref 内部 工作 | 更新日期: 2023-09-27 18:36:23

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

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

   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();
      }
   }

谢谢你的帮助。

“ref”关键字的内部工作,其中两个对象指向同一地址

您似乎误解了ref的意图。 基本上,当您将变量作为ref参数传递时,它允许被调用方完全像局部变量一样修改(原始)变量的值。 鉴于此,为什么您希望覆盖变量的值connection1也会更改分配给connection2的值?

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

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

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

connection2仍然引用原始Connection对象。 connection1已被修改为引用新的Connection对象。 connection1connection2在字面上并不是同一个参考。 connection2connection1的副本,这两个引用在一段时间内都指向同一个对象。

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

虽然柯克·沃尔的回答是正确的,但我认为当他说你误解了ref关键词时,他有点错过了重点。 这种误解很常见,但更多的是对引用类型本身性质的误解。

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

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

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

如果您记得引用类型变量存储对引用类型

实例的引用,而值类型变量直接存储值类型的实例,则跟踪起来要容易得多。

我发现这是一种比通常的"引用类型通过引用传递;值类型按值传递。 事实上,引用类型的变量(没有refout)是按值传递的,但值本身就是一个引用。 这令人困惑。 不那么令人困惑:"引用类型变量保存对该类型实例的引用"。

当然,ref 关键字使这变得有些复杂,因为 ref 参数包含对变量的引用。 这意味着引用类型 ref 参数存储对该类型实例的引用的引用。 同样,如果您想到引用类型变量包含引用的事实,则可以在保存对变量的引用的 ref 参数处停止。 这比"引用对...的引用"更容易推理。

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

如果你说 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++ 引用传递,但在引擎盖下,这些也只是指针。