2010-03-29 22 views
8

Come condividere lo stesso oggetto tra altri due oggetti? Per esempio, mi piacerebbe qualcosa in quel sapore:Come condividere una variabile tra due classi?

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"... :(

Ecco, io non voglio dare un ref al metodo Bar. Quello che voglio ottenere è qualcosa che sarebbe simile a quella in C++:

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

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

ho letto c'è qualche Rif/out roba, ma non ho potuto ottenere quello che sto chiedendo qui. Ho potuto applicare solo alcune modifiche nello scope dei metodi in cui stavo usando gli argomenti di ref/out ... Ho letto anche che potremmo usare i puntatori, ma non c'è altro modo per farlo?

+0

Nel proprio esempio specifico, le stringhe non sono un buon esempio poiché sono immutabili. – Ikaso

risposta

9

Questo non ha nulla a che fare con la condivisione di oggetti. Hai passato un riferimento a una stringa nel costruttore A. Tale riferimento è stato copiato nel membro privato foo_. Successivamente, hai chiamato B(), che ha modificato foo_ in "modificato".

In nessun momento è stato modificato str. str è una variabile locale in main. Non hai mai passato un riferimento ad esso.

Se avessi voluto cambiare str, si potrebbe avere definito B come

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

considerare:

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

nel principale:

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

Effettivamente ci farebbe fronte per farlo come suggerisce, ma non è quello che voglio fare. Qui, voglio davvero che le mie classi A e B lavorino sullo stesso oggetto assegnandole al costruttore A e B. Quindi lavorerebbero da soli sull'oggetto condiviso senza dover avere un argomento ref in ogni chiamata al metodo (voglio mantenere il mio metodo Bar senza argomenti). es .: una scatola di delimitazione orientata che segue il suo oggetto. Se posso condividere la posizione tra OBB e l'oggetto, non dovrei aggiornare la posizione OBB ogni volta che l'oggetto si muove. – Altefquatre

+1

Quindi basta passare l'oggetto a entrambi i costruttori. Questo non è quello che hai fatto nel tuo esempio. Inoltre, passare una stringa non funzionerà, poiché le stringhe sono immutabili. –

+0

ok ho capito per le lezioni. Ma se C è una struttura, questo codice non funziona più ... Come lo risolverebbe? (per esempio, sarebbe per passare Vector3 che sono struct ...) – Altefquatre

2

Vorrei dividere la mia risposta a 2 parti: 1) Se la variabile è un tipo di riferimento, è già condivisa poiché si passa il suo riferimento a tutti gli oggetti interessati. L'unica cosa che dovresti prestare attenzione è che le istanze del tipo di riferimento sono mutabili. 2) Se la variabile è un tipo di valore di quello che si dovrebbe usare ref o out o un altro wrapper che è mutabile e si può cambiare il valore all'interno del wrapper usando un metodo o una proprietà. Spero che questo aiuti.

5

Avvolgere la stringa all'interno di una classe. Devi farlo perché le stringhe sono immutabili. Qualsiasi tentativo di cambiare una stringa produce effettivamente una nuova stringa.

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 Probabilmente creerei 'StringHolder' una classe nidificata privata. – fre0n

+0

non è una cattiva idea :) – Jimmy

2

È necessario passare la paramter come riferimento per il metodo,

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

     } 
Problemi correlati