Me parece más útil pensar en los tipos de referencia como si tuvieran ID de objeto. Si uno tiene una variable de tipo de clase Car
, la declaración myCar = new Car();
le pide al sistema que cree un auto nuevo e informe su ID (digamos que es el objeto # 57); luego pone "objeto # 57" en variable myCar
. Si uno escribe Car2 = myCar;
, escribe "objeto # 57" en la variable Car2. Si uno escribe car2.Color = blue;
, eso indica al sistema que busque el automóvil identificado por Car2 (por ejemplo, el objeto # 57) y lo pinte de azul.
Las únicas operaciones que se realizan directamente en los ID de objeto son la creación de un nuevo objeto y obtener el ID, obtener un ID "en blanco" (es decir, nulo), copiar un ID de objeto a una variable o ubicación de almacenamiento que pueda contenerlo, verificar si hay dos los ID de objeto coinciden (hacen referencia al mismo objeto). Todas las demás solicitudes le piden al sistema que encuentre el objeto al que hace referencia un ID y actúe sobre ese objeto (sin afectar la variable u otra entidad que tenía el ID).
En las implementaciones existentes de .NET, es probable que las variables de objeto contengan punteros a objetos almacenados en un montón de basura recolectada, pero ese es un detalle de implementación inútil porque hay una diferencia crítica entre una referencia de objeto y cualquier otro tipo de puntero. Generalmente se supone que un puntero representa la ubicación de algo que permanecerá el tiempo suficiente para trabajar con él. Las referencias a objetos no lo hacen. Un fragmento de código puede cargar el registro SI con una referencia a un objeto ubicado en la dirección 0x12345678, comenzar a usarlo y luego ser interrumpido mientras el recolector de basura mueve el objeto a la dirección 0x23456789. Eso sonaría como un desastre, pero la basura examinará los metadatos asociados con el código, observará que el código usó SI para contener la dirección del objeto que estaba usando (es decir, 0x12345678), determine que el objeto que estaba en 0x12345678 se ha movido a 0x23456789 y actualice SI para que contenga 0x23456789 antes de que regrese. Tenga en cuenta que en ese escenario, el recolector de basura cambió el valor numérico almacenado en SI, pero se refería ael mismo objeto antes de la mudanza y después. Si antes del movimiento se refería al objeto número 23 592 creado desde el inicio del programa, continuará haciéndolo después. Curiosamente, .NET no almacena ningún identificador único e inmutable para la mayoría de los objetos; dadas dos instantáneas de la memoria de un programa, no siempre será posible saber si algún objeto en particular en la primera instantánea existe en la segunda, o si se han abandonado todos los rastros y se ha creado un nuevo objeto que se parece a él en todos los detalles observables.