Question

Est-il possible en C # d'avoir une structure avec une variable membre de type classe? Si tel est le cas, où les informations sont-elles stockées, sur la pile, le tas ou les deux?

Était-ce utile?

La solution

Oui, vous pouvez. Le pointeur sur la variable de membre de la classe est stocké sur la pile avec le reste des valeurs de la structure, et les données de l'instance de la classe sont stockées sur le tas.

Les structures peuvent également contenir des définitions de classe en tant que membres (classes internes).

Voici du code vraiment inutile qui compile et fonctionne au moins pour montrer que c'est possible:

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyStr m = new MyStr();
            m.Foo();

            MyStr.MyStrInner mi = new MyStr.MyStrInner();
            mi.Bar();

            Console.ReadLine();
        }
    }

    public class Myclass
    {
        public int a;
    }

    struct MyStr
    {
        Myclass mc;

        public void Foo()
        {
            mc = new Myclass();
            mc.a = 1;
        }

        public class MyStrInner
        {
            string x = "abc";

            public string Bar()
            {
                return x;
            }
        }
    }
}

Autres conseils

Le contenu de la classe est stocké sur le tas.

Une référence à la classe (qui est presque identique à un pointeur) est stockée avec le contenu de la structure. Le contenu de la structure est stocké selon qu’il s’agit d’une variable locale, d’un paramètre de méthode ou d’un membre d’une classe, et qu’il ait été mis en boîte ou capturé par une fermeture.

Si l'un des champs d'une structure est un type de classe, ce champ contiendra soit identité d'un objet de classe, soit une référence null. Si l’objet de classe en question est immuable (par exemple string), le stockage de son identité stockera également son contenu. Cependant, si l’objet de classe en question est mutable, le stockage de l’identité constituera un moyen efficace de stocker le contenu si et seulement si la référence ne tombe jamais entre les mains d’un code susceptible de le muter une fois stocké. le champ .

En règle générale, évitez de stocker des types de classe mutables dans une structure, sauf dans les cas suivants:

  1. Ce qui nous intéresse, c’est en fait l’identité de l’objet de classe plutôt que son contenu. Par exemple, on pourrait définir une structure `FormerControlBounds` qui contient les champs de type` Control` et `Rectangle`, et représente les` Bounds` que le contrôle a eu à un moment donné dans le but de pouvoir restaurer ultérieurement le contrôle à sa position antérieure. Le champ `Control` ne serait pas destiné à conserver une copie de l'état du contrôle, mais plutôt à identifier le contrôle dont la position devrait être restaurée. En règle générale, la structure doit éviter d’accéder aux membres modifiables de l’objet pour lequel elle contient une référence, sauf dans les cas où il est évident que cet accès fait référence à l’état modifiable en cours de l’objet en question (par exemple dans un `CaptureControlPosition` ou RestoreControlToCapturedPosition`, ou une propriété `ControlHasMoved`).
  2. Le champ est `private`, les seules méthodes qui le lisent le font pour examiner ses propriétés sans exposer l'objet lui-même au code extérieur, et les seules méthodes qui l'écrivent créeront une nouvelle objet, effectuez toutes les mutations qui vont lui arriver, puis stockez une référence à cet objet. On pourrait, par exemple, concevoir une `struct` qui se comporterait beaucoup comme un tableau, mais avec une sémantique de valeur, en tenant la table pour contenir un tableau dans un champ privé et en essayant d'écrire le tableau pour créer un nouveau tableau avec data de l'ancien, modifiez le nouveau tableau et stockez le tableau modifié dans ce champ. Notez que même si le tableau lui-même serait un type mutable, chaque instance de tableau qui serait stockée dans le champ serait effectivement immuable, car elle ne serait jamais accessible à aucun code susceptible de le muter.

Notez que le scénario n ° 1 est assez commun avec les types génériques; Par exemple, il est très courant d'avoir un dictionnaire dont les " valeurs " sont les identités des objets mutables; l'énumération de ce dictionnaire renverra les instances de KeyValuePair dont le champ Value contient ce type modifiable.

Le scénario n ° 2 est moins commun. Il n'y a hélas aucun moyen de dire au compilateur que des méthodes de structure autres que celles qui définissent les propriétés vont modifier une structure et que leur utilisation devrait donc être interdite dans des contextes en lecture seule; on peut avoir une structure qui se comporte comme un List<T>, mais avec une sémantique de valeur, et qui inclut une méthode Add, mais une tentative d'appel de <=> sur une instance de structure en lecture seule générerait un code erroné plutôt qu'une erreur de compilation. . De plus, les méthodes de mutation et les fixateurs de propriété sur de telles structures auront généralement des performances assez médiocres. De telles structures peuvent être utiles lorsqu'elles existent en tant que wrapper immuable sur une classe autrement mutable; si une telle structure n'est jamais encadrée, les performances seront souvent meilleures qu'une classe. Si elle est encadrée une seule fois (par exemple, en étant convertie en un type d’interface), les performances seront généralement comparables à une classe. Si vous encochez plusieurs fois, les performances peuvent être bien pires qu’une classe.

Ce n'est probablement pas une pratique recommandée: consultez http://msdn.microsoft.com/en-us/library/ms229017 (VS.85) .aspx

  

Les types de référence sont alloués sur le tas et la gestion de la mémoire est   manipulé par le ramasse-miettes.

     

Les types de valeur sont alloués sur la pile ou en ligne et sont désalloués.   quand ils vont hors de portée.

     

En général, les types de valeur sont moins coûteux à allouer et à désallouer.   Cependant, s’ils sont utilisés dans des scénarios nécessitant une importante   montant de la boxe et unboxing, ils fonctionnent mal par rapport à   types de référence.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top