2010-03-29 6 views
8

Comment partageriez-vous le même objet entre deux autres objets? Par exemple, je voudrais quelque chose dans ce goût:Comment partager une variable entre deux classes?

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

Ici, je ne veux pas donner un arbitre à la méthode Bar. Ce que je veux réaliser quelque chose qui ressemblerait qu'en C++:

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

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

J'ai lu il y a quelques ref/des trucs, mais je ne pouvais pas obtenir ce que je demande ici. Je pouvais seulement appliquer quelques changements dans la portée des méthodes où j'utilisais des arguments ref/out ... J'ai aussi lu que nous pouvions utiliser des pointeurs, mais n'y a-t-il pas d'autre moyen de le faire?

+0

Dans votre exemple en particulier, les chaînes ne sont pas un bon exemple car elles sont immuables. – Ikaso

Répondre

9

Cela n'a rien à voir avec le partage d'objets. Vous avez passé une référence à une chaîne dans le constructeur A. Cette référence a été copiée dans le membre privé foo_. Plus tard, vous avez appelé B(), qui a changé foo_ en "modifié".

A aucun moment vous n'avez modifié str. str est une variable locale dans main. Vous n'avez jamais passé de référence à cela.

Si vous aviez voulu changer str, vous pourriez avoir défini B comme

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

Tenir compte:

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

dans le 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

En effet, il se débrouillerait ici pour le faire comme vous le suggérez, mais ce n'est pas ce que je veux faire. Ici, je veux vraiment que mes classes A et B travaillent sur le même objet en le donnant au constructeur A et B. Ensuite, ils travailleraient seuls sur l'objet partagé sans avoir à avoir un argument ref à chaque appel de méthode (je veux garder ma méthode Bar sans arguments). Par exemple: une boîte de délimitation orientée qui suit son objet. Si je peux partager la position entre OBB et l'objet, je n'aurais pas à mettre à jour la position OBB chaque fois que l'objet se déplace. – Altefquatre

+1

Ensuite, passez simplement l'objet aux deux constructeurs. Ce n'est pas ce que vous avez fait dans votre exemple. En outre, le passage d'une chaîne ne fonctionnera pas, car les chaînes sont immuables. –

+0

ok je l'ai pour les cours. Mais si C est une structure, ce code ne fonctionne plus ... Comment le réparer? (par exemple, ce serait passer Vector3 qui sont struct ...) – Altefquatre

2

Je dissociais ma réponse à 2 parties: 1) Si la variable est un type de référence, elle est déjà partagée puisque vous passez sa référence à tous les objets intéressés. La seule chose que vous devriez faire attention est que les instances de type de référence sont mutables. 2) Si la variable est un type de valeur que vous auriez à utiliser ref ou out ou un wrapper mutable et que vous pouvez changer la valeur dans le wrapper en utilisant une méthode ou une propriété. Espérons que cela aide.

5

Enveloppez votre chaîne dans une classe. Vous devez le faire parce que les chaînes sont immuables. Toute tentative de modification d'une chaîne entraîne en réalité une nouvelle chaîne.

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 Je ferais probablement de StringHolder une classe imbriquée privée. – fre0n

+0

pas une mauvaise idée :) – Jimmy

2

Vous devez passer le paramter comme une référence à votre méthode,

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

     } 
Questions connexes