Type de référence
Le constructeur est une méthode spéciale pour initialiser une instance d'un type dans un bon état. Lors de la création d'une instance d'un type de référence, la mémoire est d'abord allouée aux champs de données de l'instance, puis les champs supplémentaires de l'objet (pointeur d'objet de type et index de bloc synchronisé), et appelle enfin le constructeur d'instance du type pour définir l'état d'initialisation de l'objet.
Lors de la construction d'un objet de type référence, la mémoire allouée à l'objet est toujours réinitialisée à 0 avant le constructeur d'instance de type électrophorèse. Tous les champs qui ne sont pas explicitement remplacés par le constructeur sont garantis d'obtenir 0 ou null. valeurs.
Contrairement à d'autres méthodes, le constructeur de force ne peut jamais être hérité, c'est-à-dire que la classe n'a que le constructeur lisse défini par la classe elle-même. Puisqu'un constructeur d'instance ne peut jamais être hérité, les modificateurs suivants ne peuvent pas être utilisés sur un constructeur d'instance : Virtuel, nouveau, remplacement, scellé et abstrait. Si la classe ne définit explicitement aucun constructeur, le compilateur C# utilisera par défaut un constructeur sans paramètre par défaut. Dans son implémentation, il appelle simplement le constructeur sans paramètre de la classe de base.
Si le modificateur de la classe est abstrait, l'accessibilité du constructeur par défaut généré par le compilateur est produit ; sinon, le constructeur recevra l'attribut d'accessibilité publique. Si la classe de base ne fournit pas de constructeur sans paramètre, la classe dérivée doit appeler explicitement un constructeur de classe de base, sinon le compilateur signalera une erreur. Si le modificateur de classe est statique (scellé et abstrait), le compilateur ne générera pas du tout de constructeur par défaut dans la définition de classe.
Un type peut définir plusieurs constructeurs d'instances. Chaque constructeur doit avoir une signature différente et chacun peut avoir des propriétés accessibles différentes. Afin de rendre le code « vérifiable », l'initialiseur de la classe doit appeler le constructeur de la classe de base avant d'accéder aux champs hérités de la classe de base. Si le constructeur de classe dérivé n’appelle pas explicitement un constructeur de classe de base, le compilateur C# génère automatiquement un appel au constructeur de classe de base par défaut. Finalement, le constructeur public sans argument de System.Object sera appelé. Le constructeur ne fait rien et renvoie directement puisque System.Object n'a pas de champs de données d'instance, son constructeur n'a rien à faire.
Dans de rares cas, il est possible de créer une instance d'un type sans appeler le constructeur d'instance. Un exemple typique est la méthode MemberwiseClone de Object. Cette méthode alloue de la mémoire, initialise les champs supplémentaires de l'objet, puis copie les propres données de l'objet source dans le nouvel objet. De plus, lors de la désérialisation d'un objet à l'aide d'un sérialiseur d'exécution, le même processus n'a pas besoin d'appeler le constructeur. La désérialisation utilise la méthode GetUnnitalizedObject ou GetSafeUninitailizedObject du type System.Runtime.Serialization.FormatterServices pour allouer de la mémoire à l'objet, et aucun constructeur ne sera appelé pendant le processus.
Astuce :
N'appelez pas de méthodes virtuelles dans le constructeur. La raison en est que si le type instancié remplace la méthode virtuelle, l'implémentation de la méthode virtuelle par le type dérivé sera exécutée, mais à ce stade, l'initialisation de tous les champs de la hiérarchie d'héritage n'est pas terminée (le constructeur du type instancié ne fonctionne pas encore). Par conséquent, l’appel de méthodes virtuelles peut entraîner un comportement imprévisible. En fin de compte, cela est dû au fait que lorsqu'une méthode virtuelle est appelée, le type réel sur lequel la méthode est exécutée n'est sélectionné qu'au moment de l'exécution.
Constructeur de type valeur (struct)
Le constructeur de type valeur (struct) fonctionne complètement différemment du constructeur de type référence (classe). Le CLR autorise toujours la création d’instances de types valeur, et il n’existe aucun moyen d’empêcher l’instanciation de types valeur. Par conséquent, les types valeur n’ont pas réellement besoin de définir un constructeur, et le compilateur C# n’incorporera pas du tout de constructeur par défaut sans argument pour les types valeur. Regardons le code suivant :
internal struct Point {
public int m_x, m_y;
}
interne scellé class Reactangel
{
public Point m_TopLeft, m_bottomRight;
}
Afin de construire un rectangle, l'opérateur new doit être utilisé et le constructeur doit être précisé. Dans cet exemple, le constructeur par défaut généré automatiquement par le compilateur C# est appelé. Allouez de la mémoire pour Reatangle, qui contient deux instances du type de valeur Point. Compte tenu des performances, le CLR n'appellera pas activement le constructeur pour chaque champ de type valeur contenu dans le type référence. Cependant, comme mentionné précédemment, les champs de type valeur seront initialisés à 0 ou null.
Le CLR permet de définir des constructeurs pour les types valeur, mais ils doivent être explicitement appelés pour qu'ils soient exécutés.
Point de structure interne {
public int m_x, m_y;
Point public (int x, int y)
{
m_x = x;
m_y = y;
}
}
classe scellée interne Reactangel
{
public Point m_TopLeft, m_bottomRight;
public Reactangel()
{
this.m_TopLeft = nouveau Point(1 ,2);
this.m_bottomRight = new Point(100,200);
}
}
Les constructeurs d'instances de types valeur ne seront exécutés que lorsqu'ils sont explicitement appelés. Par conséquent, si le constructeur de Rectangle n'utilise pas l'opérateur new pour appeler le constructeur de Point afin d'initialiser les champs m_TopLeft et m_bottomRight de Reatangle, alors les champs m_x et m_y dans les deux champs de point seront 0.
Réécrire le code ci-dessus :
internal struct Point {
public int m_x, m_y;
public Point()
{
m_x = 5;
m_y = 6;
}
}
classe scellée interne Reactangel
{
public Point m_TopLeft, m_bottomRight;
public Reactangel()
{
}
}
Maintenant, lors de la construction d'une nouvelle classe Rectangle, dans quelle mesure les champs m_x et m_y dans les deux champs Point seront-ils initialisés, est-ce 0 ou 5 ?
Peut-être pensez-vous que le compilateur C# générera du code dans le constructeur de Reactangel et appellera automatiquement le constructeur sans argument par défaut de Point pour les deux champs de Reactangel. Toutefois, pour améliorer les performances d'exécution de votre application, le compilateur C# ne génère pas automatiquement ce code. En fait, même si un type valeur fournit un constructeur sans paramètre, de nombreux compilateurs ne généreront jamais de code pour l'appeler. Afin d'implémenter un constructeur sans paramètre de type valeur, le développeur doit ajouter du code qui appelle explicitement le constructeur de type valeur. Mais les deux champs de Point' seront-ils initialisés à 0 pour cette raison ? Le résultat est :
Le compilateur C# ne permet délibérément pas aux types valeur de définir des constructeurs sans paramètre afin de Les développeurs ne savent pas quand ce constructeur est appelé. Puisqu'un constructeur sans paramètre ne peut pas être défini, le compilateur ne générera jamais de code qui l'appelle automatiquement. Sans constructeur sans paramètre, les champs de types valeur sont toujours initialisés à 0 ou null.
Constructeur de type :
est également appelé constructeur statique, constructeur de classe ou initialiseur de type. Les constructeurs de types peuvent être utilisés avec des types référence et des types valeur. Le but d'un constructeur d'instance est de définir l'état initial d'une instance d'un type. En conséquence, le rôle du constructeur de type est de définir l’état initial du type. Le type ne définit pas de constructeur de type par défaut. S'il est défini, il ne peut y en avoir qu'un. De plus, les constructeurs de types n’ont jamais de paramètres.
classe scellée interne SomeRefType {
static SomeRefType()
{
//Lors de votre première visite, exécutez le code ici
}
}
structure interne SomeValType
{
static SomeValType()
{
//Lors de votre première visite, exécutez le code ici
}
>
On peut voir que la définition d'un constructeur de type est similaire pour définir un constructeur d'instance sans paramètre. La différence est qu'il doit être marqué comme statique. De plus, les constructeurs de types sont toujours privés. La raison pour laquelle il est privé est d'empêcher tout développeur d'écrire du code pour l'appeler, et le CLR est toujours responsable de ses appels.
Astuce :
Bien que vous puissiez définir un constructeur de type dans un type valeur, vous ne devriez jamais le faire car le CLR n'appelle parfois pas le constructeur statique du type valeur : par exemple
structure interne SomeValType
{
static SomeValType()
{
Console.WriteLine("Cette phrase ne sera jamais affichée" ) ;
}
public int m_x;
}
class Program
{
static void Main ( string[] args)
{
SomeValType[] a = new SomeValType[10];
a[0].m_x = 123;
Console.WriteLine(a[0].m_x);
Console.ReadKey();
}
}
Le code du type constructeur uniquement Peut accéder aux champs statiques du type, et son utilisation non conventionnelle est d'initialiser ces champs.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!