2010-05-03 15 views
5

Me preguntaba cómo se podría almacenar una referencia a un objeto en .net.Almacenar una referencia a un objeto en C#

Eso es, me gustaría algo así como el siguiente código (nota, por supuesto, que el siguiente código puede ser muy lejos de cómo realmente hacerlo):

class Test 
{ 
    private /*reference to*/ Object a; 
    public Test(ref int a) 
    { 
     this.a = a; 
     this.a = ((int)this.a) + 1; 
    } 
    public Object getA() { return this.a; } 
} 
/* 
* ... 
*/ 
static void Main(string[] args) 
{ 
    int a; 
    a=3; 
    Test t = new Test(ref a); 
    Console.WriteLine(a); 
    Console.WriteLine(t.getA()); 
    Console.ReadKey(); 
} 

para producir el siguiente resultado:

4 
4 

Idealmente, me gustaría hacer esto sin escribir una clase contenedora alrededor del número entero.

En otras palabras, creo que quiero punteros en .Net.

+4

Le recomiendo que lea sobre la diferencia entre "tipos de valores" y "tipos de referencia" en el CLR. –

+2

Hay punteros en .NET pero no se atreve a usarlos para este LOL –

+0

@JohnSaunders ¿Cuál es la diferencia entre [C# -language] y [C#]? ¿No son sinónimos? No lo entiendo –

Respuesta

36

No puede almacenar referencias a las variables en .NET, punto. Puede almacenar referencias a objetos, pero no referencias a variables.

La razón es que si se le permitiera almacenar referencias a variables arbitrarias, entonces podría almacenar referencias a variables locales. Si puede almacenar referencias a variables locales, entonces el tiempo de ejecución no puede usar la optimización de almacenamiento de variables locales en el grupo de memoria de corta duración, es decir, la pila.

Ahora, incluso si pudiera hacer eso, la operación que está describiendo no es segura por un motivo diferente. Tiene una variable de campo (muy mal nombrado) "a" de tipo "referencia a variable de objeto" y una variable local (muy mal y de nombre confuso) "a" de tipo "referencia a variable int". Incluso si pudiera almacenar una referencia a una variable, no tiene sentido almacenar una referencia a una variable int en algo del tipo "referencia a la variable de objeto" porque esos dos tipos lógicamente no son compatibles. Las operaciones que puede realizar en ellos son diferentes; una referencia a una variable de objeto puede tener una cadena escrita en ella; una referencia a una variable int no puede.

Tal vez estoy entendiendo mal pero ¿una variable como el entero de arriba no se encajonaría en un objeto que luego podría almacenarse como referencia?

Usted está confundiendo las referencias a objetos con referencias a las variables . Es confuso que usemos la misma terminología para lo que en realidad son dos cosas diferentes.

Sí, el boxeo convierte un tipo de valor, como int, en un tipo de referencia, como objeto. Eso NO TIENE ABSOLUTAMENTE NADA QUE VER con referencias a variables.

Cuando hace una referencia a una variable, está creando un alias para esa variable. Cuando dice

void M(ref int y) { y = 123; } 
... 
int x = 0; 
M(ref x); 

está diciendo "xey son dos nombres diferentes para la misma variable".

Ahora, si lo que quieres hacer es representar la noción de "He capturado una variable y quiero ser capaz de leer y escribir que" a continuación, utilizar delegados:

class Ref<T> 
{ 
    private Func<T> getter; 
    private Action<T> setter; 
    public Ref(Func<T> getter, Action<T> setter) 
    { 
     this.getter = getter; 
     this.setter = setter; 
    } 
    public T Value 
    { 
     get { return getter(); } 
     set { setter(value); } 
    } 
} 
... 
int abc = 123; 
var refabc = new Ref<int>(()=>abc, x=>{abc=x;}); 
... now you can pass around refabc, store it in a field, and so on 
refabc.Value = 456; 
Console.WriteLine(abc); // 456 
Console.WriteLine(refabc.Value); // 456 

sentido?

+0

Tal vez estoy malinterpretando, pero ¿una variable como el entero anterior no se encajonaría en un objeto que luego podría almacenarse como referencia? –

+0

Los cierres capturan las referencias de variables locales. –

+0

Lo hace. Gracias. Supongo que estoy demasiado acostumbrado a C. –

9

C# no tiene el concepto de una variable de referencia similar a la de C++ int& a. Hay soluciones. Uno es utilizar cierres:

class Test 
{ 
    private Func<int> get_a; 
    private Action<int> set_a; 
    public Test(Func<int> get_a, Action<int> set_a) 
    { 
     this.get_a = get_a; 
     this.set_a = set_a; 
     this.set_a(this.get_a() + 1); 
    } 
    public Object getA() { return this.get_a(); } 
} 
/* 
* ... 
*/ 
static void Main(string[] args) 
{ 
    int a; 
    a=3; 
    Test t = new Test(() => a, n => { a = n; }); 
    Console.WriteLine(a); 
    Console.WriteLine(t.getA()); 
    Console.ReadKey(); 
} 

No estoy frente a VS, así que disculpen cualquier paso en falso embarazosas.

+2

+1, no es algo que usaría en el código de producción; pero lindo, sin embargo, – Pierreten

+2

Aparentemente, las grandes mentes piensan igual. :-) –

Cuestiones relacionadas