2010-03-29 21 views
8

¿Cómo compartirías el mismo objeto entre otros dos objetos? Por ejemplo, me gustaría algo en ese sabor:¿Cómo compartir una variable entre dos clases?

class A 
{ 
    private string foo_; // It could be any other class/struct too (Vector3, Matrix...) 

    public A (string shared) 
    { 
     this.foo_ = shared; 
    } 

    public void Bar() 
    { 
     this.foo_ = "changed"; 
    } 
} 

... 
// inside main 
string str = "test"; 
A a = new A(str); 

Console.WriteLine(str); // "test" 
a.Bar(); 
Console.WriteLine(str); // I get "test" instead of "changed"... :(

Aquí, no quiero dar una referencia al método de bar. Lo que quiero lograr es algo que se vería que en C++:

class A 
{ 
    int* i; 
public: 
    A(int* val); 
}; 

A::A (int* val) 
{ 
    this->i = val; 
} 

leí hay algo de ref/hacia fuera la materia, pero no pude conseguir lo que estoy pidiendo aquí. Solo pude aplicar algunos cambios en el alcance de los métodos donde estaba usando los argumentos de ref/out ... También leí que podíamos usar punteros, ¿pero no hay otra manera de hacerlo?

+0

Específicamente en su ejemplo, las cadenas no son un buen ejemplo ya que son inmutables. – Ikaso

Respuesta

9

Esto no tiene nada que ver con compartir objetos. Pasaste una referencia a una cadena en el constructor A. Esa referencia se copió en el miembro privado foo_. Más tarde, llamó al B(), que cambió foo_ a "changed".

En ningún momento modificó str. str es una variable local en main. Nunca pasaste una referencia a eso. B

Si se hubiera querido cambiar str, se podría haber definido como

public void Bar(ref string s) 
    { 
    this.foo_ = "changed"; 
    s = this.foo_; 
    } 

considerar:

public class C 
{ 
    public int Property {get;set;} 
} 

public class A 
{ 
    private C _c; 
    public A(C c){_c = c;} 

    public void ChangeC(int n) {_c.Property = n;} 
} 

public class B 
{ 
    private C _c; 
    public B(C c){_c = c;} 

    public void ChangeC(int n) {_c.Property = n;} 
} 

en el principal:

C myC = new C() {Property = 1;} 
A myA = new A(myC); 
B myB = new B(myC); 

int i1 = myC.Property; // 1 
myA.ChangeC(2); 
int i2 = myC.Property; // 2 
myB.ChangeC(3); 
int i3 = myC.Property; // 3 
+0

De hecho, podría hacer frente aquí para hacerlo como usted sugiere, pero no es lo que quiero hacer. Aquí, realmente quiero que mi clase A y B trabajen en el mismo objeto entregándolo al constructor A y B. Luego trabajarían solos en el objeto compartido sin tener que tener un argumento ref en cada llamada al método (quiero mantener mi método Bar sin argumentos). p. Ej .: una Caja delimitadora orientada que sigue su objeto. Si puedo compartir la posición entre OBB y el objeto, no tendría que actualizar la posición OBB cada vez que se mueve el objeto. – Altefquatre

+1

Luego solo pase el objeto a ambos constructores. Eso no es lo que hiciste en tu ejemplo. Además, pasar una cadena no funcionará, ya que las cadenas son inmutables. –

+0

ok, lo consigo para las clases. Pero si C es una estructura, este código ya no funciona ... ¿Cómo lo arreglarías? (por ejemplo, sería pasar Vector3 que son struct ...) – Altefquatre

2

sin dividir mi respuesta a 2 partes: 1) Si la variable es un tipo de referencia que ya está compartida, ya que pasa su referencia a todos los objetos interesados. Lo único que debe prestar atención es que las instancias de tipo de referencia son mutables. 2) Si la variable tiene un valor de tipo, debe usar ref o out o alguna envoltura que es mutable y puede cambiar el valor dentro del contenedor utilizando un método o una propiedad. Espero que ayude.

5

Envuelva su cadena dentro de una clase. Necesitas hacer esto porque las cadenas son inmutables. Cualquier intento de cambiar una cadena en realidad da como resultado una nueva cadena.

class Foo { 
    class StringHolder { 
     public string Value { get; set; } 
    } 
    private StringHolder holder = new StringHolder(); 
    public string Value { 
     get { return holder.Value; } 
     set { holder.Value = value; } 
    } 
    public Foo() { } 
    // this constructor creates a "linked" Foo 
    public Foo(Foo other) { this.holder = other.holder; } 
} 

// .. later ... 

Foo a = new Foo { Value = "moose" }; 
Foo b = new Foo(a); // link b to a 
b.Value = "elk"; 
// now a.Value also == "elk" 
a.Value = "deer"; 
// now b.Value also == "deer" 
+0

+1 Sin embargo, probablemente haría de 'StringHolder' una clase anidada privada. – fre0n

+0

no es una mala idea :) – Jimmy

2

Es necesario pasar el parametro como una referencia a su método,

class A 
     { 
      private string foo_; // It could be any other class/struct too (Vector3, Matrix...) 

      public A(string shared) 
      { 
       this.foo_ = shared; 
      } 

      public void Bar(ref string myString) 
      { 
       myString = "changed"; 
      } 
     } 

static void Main() 
     { 
      string str = "test"; 
      A a = new A(str); 

      Console.WriteLine(str); // "test" 
      a.Bar(ref str); 
      Console.WriteLine(str); 

     } 
Cuestiones relacionadas