web-dev-qa-db-fra.com

Quel est le meilleur moyen d'accéder au champ de la classe englobante à partir de la classe imbriquée?

Dites si j'ai une liste déroulante dans un formulaire et que j'ai une autre classe imbriquée à l'intérieur de cette classe . Maintenant, quel est le meilleur moyen d'accéder à cette liste déroulante depuis la classe imbriquée? 

53
Learner

Contrairement à Java, une classe imbriquée n'est pas une "classe interne" spéciale, vous devez donc passer une référence. Raymond Chen propose ici un exemple décrivant les différences: Les classes imbriquées C # ressemblent aux classes imbriquées C++, et non aux classes internes Java .

Voici un exemple où le constructeur de la classe imbriquée se voit transmettre l'instance de la classe externe pour une référence ultérieure. 

// C#
class OuterClass 
{
    string s;
    // ...
    class InnerClass 
    {
       OuterClass o_;
       public InnerClass(OuterClass o) { o_ = o; }
       public string GetOuterString() { return o_.s; }
    }
    void SomeFunction() {
        InnerClass i = new InnerClass(this);
        i.GetOuterString();
    }

}

Notez que l'InnerClass peut accéder à la "s" de l'OuterClass, je n'ai pas modifié le code de Raymond (comme je l'ai lié ci-dessus), donc rappelez-vous que "string s;" est private car aucune autre autorisation d'accès n'a été spécifiée. 

68
Ray Hayes

Les types imbriqués ne ressemblent pas aux classes internes de Java - il n'y a pas d'instance inhérente du type contenant. (Ils ressemblent davantage à des classes imbriquées statiques en Java.) Ce sont en réalité des classes séparées, avec deux distinctions:

  • Si le type contenant est générique, le type imbriqué est effectivement paramétré par le type contenant, par ex. Outer<int>.Nested n'est pas la même chose que Outer<string>.Nested.
  • Les types imbriqués ont accès aux membres privés dans le type contenant.
30
Jon Skeet

Contrairement à Java, en C #, il n’ya pas de référence implicite à une instance de la classe englobante.

Vous devez passer une telle référence à la classe imbriquée. Pour ce faire, utilisez généralement le constructeur de la classe imbriquée.

public partial class Form1 : Form
{
    private Nested m_Nested;

    public Form1()
    {
        InitializeComponent();

        m_Nested = new Nested(this);
        m_Nested.Test();
    }

    private class Nested
    {
        private Form1 m_Parent;

        protected Form1 Parent
        {
            get
            {
                return m_Parent;
            }
        }

        public Nested(Form1 parent)
        {
            m_Parent = parent;
        }

        public void Test()
        {
            this.Parent.textBox1.Text = "Testing access to parent Form's control";
        }
    }
}
12
Jason Kresowaty

Membres statiques

Puisque personne ne l’a mentionné jusqu’à présent: En fonction de votre situation, si la variable membre peut également être static , vous pourrez simplement y accéder de la manière suivante.

class OuterClass
{
    private static int memberVar;

    class NestedClass 
    {
        void SomeFunction() { OuterClass.memberVar = 42; }
    }
}

Sidenote: J'ai marqué memberVar à dessein (et de manière redondante) avec private pour illustrer la capacité donnée de la classe imbriquée d'accéder aux membres privés de sa classe externe.

Attention/S'il vous plaît envisager

Dans certaines situations, cela pourrait être le moyen le plus simple de contourner le problème, mais ...

  • Statique signifie également que la variable sera partagée entre tous les objets d'instance, avec tous les inconvénients/conséquences qu'il y a (sécurité des threads, etc.).

  • Statique signifie également que cela ne fonctionnera évidemment pas si vous avez plus d'une instance de la classe parent et que la variable doit contenir une valeur individuelle pour chaque instance.

Donc, dans la plupart des cas, vous voudrez peut-être adopter une approche différente ...

Passer une référence

Comme la plupart des gens l'ont suggéré (et parce que c'est aussi la réponse la plus correcte), voici un exemple de transmission d'une référence à l'instance de la classe externe.

class OuterClass
{
    private int memberVar;
    private NestedClass n;

    OuterClass()   { n = new NestedClass(this); }


    class NestedClass
    {
        private OuterClass parent;

        NestedClass(OuterClass p) { parent = p; }
        SomeFunction() { parent.memberVar = 42; }
    }
}
7
Levit

Une autre méthode, utile dans certaines circonstances, consiste à dériver la classe imbriquée de la classe externe. Ainsi:

class Outer()
{
    protected int outerVar;
    class Nested() : Outer
    {
        //can access outerVar here, without the need for a 
        // reference variable (or the associated dot notation).
    }
}

J'ai utilisé cette technique notamment dans le cadre de Tests unitaires structurés . (Cela peut ne pas s'appliquer à la question particulière du PO, mais cela peut être utile avec les classes imbriquées en général, comme dans le cas de cette question "en double": " Puis-je accéder aux objets de classe externes dans la classe intérieure ")

3
kmote

Corrigez-moi si je me trompe, vous essayez de traiter le contrôle externe de la classe interne, vous avez donc rencontré ce problème. Une meilleure façon de le faire serait de gérer les affaires de manière événementielle. Utilisez un modèle Observer, enregistrez un écouteur sur le contrôle externe (votre classe imbriquée/interne sera l'écouteur). Rend la vie plus simple. Je crains que ce ne soit pas la réponse à laquelle vous vous attendiez!

1
questzen

Vous pouvez passer la classe englobante en tant que paramètre au constructeur de la classe imbriquée, comme ceci:

private NestedClass _nestedClass;
public ParentClass() 
{
   _nestedClass = new NestedClass(this);
}

Les classes imbriquées ne sont généralement pas recommandées et doivent être privées et/ou internes. À mon avis, ils sont parfois utiles.

0
mannu

envoie la classe maître en tant que paramètre de constructeur à la classe imbriquée (interne).

0
Hamid Jolany