Restreindre l’accès aux propriétés
Une classe peut spécifier la façon dont chacun de ses membres est accessible pour coder en dehors de la classe. Les méthodes et variables qui ne sont pas destinées à être utilisées à partir de l’extérieur de la classe ou de l’assembly peuvent être masquées pour limiter le risque d’erreurs de codage ou d’attaques malveillantes.
Certaines méthodes et propriétés sont destinées à être appelées ou accessibles à partir du code en dehors d’une classe, appelée code client. D’autres méthodes et propriétés peuvent être utilisées uniquement dans la classe elle-même. Il est important de limiter l’accessibilité de votre code afin que seul le code client prévu puisse y accéder. Vous spécifiez la façon dont vos types et leurs membres sont accessibles au code client à l’aide des modificateurs d’accès suivants :
-
public: le type ou le membre est accessible par tout autre code dans le même assembly ou un autre assembly qui le référence. -
protected: le type ou le membre est accessible uniquement par du code dans la même classe ou une classe dérivée. -
internal: le type ou le membre est accessible par n’importe quel code dans le même assembly, mais pas à partir d’un autre assembly. -
protected internal: le type ou le membre est accessible par n’importe quel code dans le même assembly, ou par toute classe dérivée d’un autre assembly. -
private: le type ou le membre est accessible uniquement par du code dans la même classe ou struct. -
private protected: le type ou le membre est accessible uniquement par du code dans le même assembly, et uniquement par du code dans la même classe ou une classe dérivée.
Les membres de classe sont affectés private accès par défaut.
Modificateurs d’accès sur les propriétés et les accesseurs
Jusqu’à ce stade du module, nous nous sommes concentrés sur les propriétés qui incluent à la fois des get et des accesseurs set. Ces propriétés sont appelées propriétés en lecture-écriture. En plus des propriétés en lecture-écriture, vous pouvez créer des propriétés en lecture seule ou accorder une accessibilité différente aux accesseurs set et get.
Par défaut, les accesseurs get et set ont le même niveau d’accessibilité que la propriété à laquelle ils appartiennent. Toutefois, vous pouvez restreindre l’accessibilité de l’accesseur get ou set. Les modificateurs d’accès sont utiles lorsque vous souhaitez restreindre l’accès à la propriété elle-même, mais autorisez toujours l’accès à la valeur de la propriété via un accesseur get.
Supposons que vous disposez d’une classe Person qui ne doit activer que la modification de la valeur de la propriété FirstName à partir d’autres méthodes de la classe. Vous pouvez donner à l’accesseur set l’accessibilité privée au lieu d’une accessibilité interne ou publique :
public class Person
{
public string? FirstName { get; private set; }
// Omitted for brevity.
}
La propriété FirstName peut être lue à partir de n’importe quel code, mais elle ne peut être affectée qu’à partir du code dans la classe Person.
Vous pouvez ajouter n’importe quel modificateur d’accès restrictif aux accesseurs set ou get. Un modificateur d’accès sur un accesseur individuel doit être plus restrictif que l’accès de la propriété. Le code précédent est légal, car la propriété FirstName est public, mais l’accesseur set est private. Vous n’avez pas pu déclarer de propriété private avec un accesseur public. Les déclarations de propriété peuvent également être déclarées protected, internal, protected internalou même private.
Il existe deux modificateurs d’accès spéciaux pour les accesseurs set :
- Un accesseur
setpeut avoirinitcomme modificateur d’accès. Cet accesseursetne peut être appelé qu’à partir d’un initialiseur d’objet ou des constructeurs du type. Il est plus restrictif queprivatesur l’accesseurset. - Une propriété implémentée automatiquement peut déclarer un accesseur
getsans accesseurset. Dans ce cas, le compilateur autorise l’accèssetà être appelé uniquement à partir des constructeurs du type. Il est plus restrictif que l’accesseurinitsur l’accesseurset.
Tenez compte des mises à jour suivantes de la classe Person :
public class Person
{
public Person(string firstName) => FirstName = firstName;
public string FirstName { get; }
// Omitted for brevity.
}
L’exemple précédent nécessite que les appelants utilisent le constructeur qui inclut le paramètre FirstName. Les appelants ne peuvent pas utiliser d’initialiseurs d’objet pour affecter une valeur à la propriété. Pour prendre en charge les initialiseurs, vous pouvez rendre l’accesseur set un accesseur init, comme indiqué dans le code suivant :
public class Person
{
public Person() { }
public Person(string firstName) => FirstName = firstName;
public string? FirstName { get; init; }
// Omitted for brevity.
}
Ces modificateurs sont souvent utilisés avec le modificateur required pour forcer l’initialisation appropriée.
Restreindre l’accessibilité de l’accesseur
Dans certains cas, il est utile de restreindre l’accès au get ou set accesseur. En règle générale, vous limitez l’accessibilité de l’accesseur set tout en conservant l’accesseur get accessible publiquement.
Par exemple:
private string _name = "Hello";
public string Name
{
get
{
return _name;
}
protected set
{
_name = value;
}
}
Dans cet exemple, une propriété appelée Name définit un accesseur get et set. L’accesseur get reçoit le niveau d’accessibilité de la propriété elle-même, public dans ce cas, tandis que l’accesseur set est explicitement limité en appliquant le modificateur d’accès protected au accesseur lui-même.
Restrictions sur les modificateurs d’accès sur les accesseurs
L’utilisation des modificateurs d’accesseur sur les propriétés ou les indexeurs est soumise à ces conditions :
- Vous ne pouvez utiliser des modificateurs d’accesseur que si la propriété a à la fois des
setet des accesseursget. Dans ce cas, le modificateur est autorisé sur un seul des deux accesseurs. - Le niveau d’accessibilité sur l’accesseur doit être plus restrictif que le niveau d’accessibilité sur la propriété ou l’indexeur lui-même.
Propriétés statiques en lecture seule
L’exemple suivant illustre l’utilisation des propriétés d’instance et statiques dans une classe.
La classe Employee a une propriété statique nommée Counter qui suit le nombre d’instances de classe créées. La propriété Counter est en lecture seule, ce qui signifie qu’elle est accessible à partir de l’extérieur de la classe, mais qu’elle n’est pas modifiée. La propriété Counter est également static, ce qui signifie que vous accédez à la valeur de Counter à l’aide de la classe Employee, et non les instances employee1 ou employee2 de la classe.
public class Employee
{
public static int NumberOfEmployees;
private static int _counter;
private string _name;
// A read-write instance property:
public string Name
{
get => _name;
set => _name = value;
}
// A read-only static property:
public static int Counter => _counter;
// A Constructor:
public Employee() => _counter = ++NumberOfEmployees; // Calculate the employee's number:
}
public class Program
{
static void Main(string[] args)
{
// Create an initial instance of the Employee class
Employee employee1 = new Employee { Name = "NameOne" };
// Display the name and counter values
Console.WriteLine($"Employee 1: Name = {employee1.Name}, Counter = {Employee.Counter}");
// Create a second instance of the Employee class
Employee employee2 = new Employee { Name = "NameTwo" };
// Display the name and counter values
Console.WriteLine($"Employee 2: Name = {employee2.Name}, Counter = {Employee.Counter}");
employee2.Name = "NameThree";
// Display the name and counter values
Console.WriteLine($"Employee 2: Name = {employee2.Name}, Counter = {Employee.Counter}");
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
La classe Employee a les membres suivants :
-
NumberOfEmployees: champ statique public qui effectue le suivi du nombre total d’instances d’employés créées. Étant statique, il est partagé entre toutes les instances de la classe Employee. -
_counter: champ statique privé utilisé pour affecter un numéro unique à chaque instance Employee. Il est également partagé entre toutes les instances. -
_name: champ d’instance privée qui stocke le nom de l’employé. Elle est spécifique à chaque instance de la classe Employee. -
Name: propriété d’instance en lecture-écriture publique qui fournit l’accès au champ _name. L’accesseurgetretourne la valeur de_name, et l’accesseursetattribue une nouvelle valeur à_name. -
Counter: propriété statique en lecture seule publique qui fournit l’accès au champ_counter. L’accesseurgetretourne la valeur de_counter. La propriétéCounterest associée à la classe plutôt qu’aux objets, car elle est définie comme une propriété statique.
Les deux champs statiques sont initialisés lorsque la classe est chargée en mémoire avant la création d’instances de la classe. En C#, les champs statiques sont initialisés sur leurs valeurs par défaut s’ils ne sont pas initialisés explicitement. Pour int champs, la valeur par défaut est 0.
Les propriétés statiques et les champs appartiennent à la classe elle-même, et non à une instance particulière de la classe. Toutes les instances de la classe partagent les mêmes propriétés et champs statiques.
Le constructeur incrémente le champ statique NumberOfEmployees de 1 et affecte la nouvelle valeur au champ statique _counter. Cette approche garantit que chaque instance de Employee obtient un nombre unique.
Accesseurs privés
Considérez le code suivant qui implémente des propriétés en lecture-écriture :
class Person
{
private string _name = "N/A";
private int _age = 0;
// Declare a Name property of type string:
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
// Declare an Age property of type int:
public int Age
{
get
{
return _age;
}
set
{
_age = value;
}
}
}
class TestPerson
{
static void Main()
{
// Create a new Person object:
Person person = new Person();
// Print out the name and the age associated with the person:
Console.WriteLine($"Person details - Name = {person.Name}, Age = {person.Age}");
// Set some values on the person object:
person.Name = "NameOne";
person.Age = 99;
Console.WriteLine($"Person details - Name = {person.Name}, Age = {person.Age}");
// Increment the Age property:
person.Age += 1;
Console.WriteLine($"Person details - Name = {person.Name}, Age = {person.Age}");
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Person details - Name = N/A, Age = 0
Person details - Name = NameOne, Age = 99
Person details - Name = NameOne, Age = 100
*/
Dans cet exemple, la classe Person inclut des propriétés Name et Age. Les propriétés sont publiques et incluent tous deux des accesseurs get et set. Les accesseurs publics permettent à n’importe quel objet de lire et d’écrire ces propriétés.
Parfois, il s’agit d’exclure l’un des accesseurs. Vous pouvez omettre l’accesseur set pour que la propriété soit en lecture seule :
public string Name
{
get
{
return _name;
}
}
Vous pouvez également exposer un accesseur publiquement, mais rendre l’autre privé ou protégé.
public string Name
{
get
{
return _name;
}
private set
{
_name = value;
}
}