Utilisation de propriétés (Guide de programmation C#)
Les propriétés combinent des aspects à la fois des champs et des méthodes. Aux yeux de l'utilisateur d'un objet, une propriété semble être un champ. L'accès à la propriété demande exactement la même syntaxe. Pour l'implémenteur d'une classe, une propriété est constituée d'un ou de deux blocs de code, représentant un accesseur get et/ou un accesseur set. Le bloc de code de l'accesseur get est exécuté à la lecture de la propriété ; le bloc de code de l'accesseur set est exécuté à l'assignation d'une nouvelle valeur à la propriété. Une propriété sans accesseur set est considérée comme étant en lecture seule. Une propriété sans accesseur get est considérée comme étant en écriture seule. Une propriété comportant les deux accesseurs est en lecture-écriture.
Contrairement aux champs, les propriétés ne sont pas classées en tant que variables. Par conséquent, vous ne pouvez pas passer une propriété en tant que paramètre ref (référence C#) ou out (référence C#).
Les propriétés ont de multiples utilisations : elles peuvent valider des données avant d'autoriser une modification ; elles peuvent exposer de façon transparente sur une classe des données récupérées de quelque autre source, telle qu'une base de données ; elles peuvent effectuer une action à la suite d'une modification de données, par exemple déclencher un événement ou modifier les valeurs d'autres champs.
Pour déclarer les propriétés dans le bloc de classe, vous devez spécifier le niveau d'accès du champ, suivi du type puis du nom de la propriété, et enfin d'un bloc de code qui déclare un accesseur get et/ou un accesseur set. Par exemple :
public class Date
{
private int month = 7; // Backing store
public int Month
{
get
{
return month;
}
set
{
if ((value > 0) && (value < 13))
{
month = value;
}
}
}
}
Dans cet exemple, Month est déclaré comme une propriété afin que l'accesseur set puisse s'assurer que la valeur Month est définie entre 1 et 12. La propriété Month utilise un champ privé pour suivre la valeur réelle. L'emplacement réel des données d'une propriété est souvent appelé « magasin de stockage » de la propriété. Il est courant pour les propriétés d'utiliser des champs privés comme magasin de stockage. Le champ reçoit un marqueur indiquant qu'il est privé pour garantir qu'il ne pourra être modifié que par appel de la propriété. Pour plus d'informations sur les restrictions d'accès public et privé, consultez Modificateurs d'accès (Guide de programmation C#).
Les propriétés implémentées automatiquement fournissent une syntaxe simplifiée pour les déclarations de propriété simples. Pour plus d'informations, consultez Propriétés implémentées automatiquement (Guide de programmation C#).
Accesseur get
Le corps de l'accesseur get ressemble à celui d'une méthode. Il doit retourner une valeur de type de propriété. L'exécution de l'accesseur get équivaut à la lecture de la valeur du champ. Par exemple, lorsque vous retournez la variable privée de l'accesseur get et que les optimisations sont activées, le compilateur fait en sorte que l'appel à la méthode d'accesseur get soit inline pour qu'il n'y ait pas surcharge d'appels à la méthode. Toutefois, une méthode d'accesseur get virtuelle ne peut pas être inline, car le compilateur ne sait pas au moment de la compilation quelle méthode sera réellement appelée à l'exécution. Voici un accesseur get qui retourne la valeur d'un champ privé name :
class Person
{
private string name; // the name field
public string Name // the Name property
{
get
{
return name;
}
}
}
Lorsque vous référencez la propriété, sauf dans le cas où il s'agit de la cible d'une assignation, l'accesseur get est appelé pour lire la valeur de la propriété. Par exemple :
Person person = new Person();
//...
System.Console.Write(person.Name); // the get accessor is invoked here
L'accesseur get doit se terminer dans une instruction return ou throw, et le contrôle ne peut pas s'écouler du corps de l'accesseur.
Modifier l'état de l'objet à l'aide de l'accesseur get n'est pas une bonne habitude de programmation. Par exemple, l'accesseur ci-dessous a pour effet secondaire de modifier l'état de l'objet à chaque accès au champ number.
private int number;
public int Number
{
get
{
return number++; // Don't do this
}
}
L'accesseur get peut être utilisé pour retourner la valeur du champ ou pour la calculer et la retourner. Par exemple :
class Employee
{
private string name;
public string Name
{
get
{
return name != null ? name : "NA";
}
}
}
Dans le segment de code précédent, si vous n'assignez pas de valeur à la propriété Name, une valeur NA est retournée.
Accesseur set
L'accesseur set est semblable à une méthode dont le type de retour est void. Il utilise un paramètre implicite nommé value, dont le type est celui de la propriété. Dans l'exemple suivant, un accesseur set est ajouté à la propriété Name :
class Person
{
private string name; // the name field
public string Name // the Name property
{
get
{
return name;
}
set
{
name = value;
}
}
}
Lorsque vous assignez une valeur à la propriété, l'accesseur set est appelé à l'aide d'un argument qui fournit la nouvelle valeur. Par exemple :
Person person = new Person();
person.Name = "Joe"; // the set accessor is invoked here
System.Console.Write(person.Name); // the get accessor is invoked here
C'est une erreur d'utiliser le nom du paramètre implicite value pour une déclaration de variable locale dans un accesseur set.
Notes
Les propriétés peuvent être marquées comme public, private, protected, internal ou protected internal. Ces modificateurs d'accès définissent la façon dont les utilisateurs de la classe ont accès à la propriété. Les accesseurs get et set d'une même propriété peuvent avoir des modificateurs d'accès différents. Par exemple, get peut être public pour autoriser l'accès en lecture seule depuis l'extérieur du type et set peut être private ou protected. Pour plus d'informations, consultez Modificateurs d'accès (Guide de programmation C#).
Une propriété peut être déclarée comme étant statique à l'aide du mot clé static. Elle devient ainsi disponible aux appelants à tout moment, même s'il n'existe aucune instance de la classe. Pour plus d'informations, consultez Classes statiques et membres de classe statique (Guide de programmation C#).
Une propriété peut être marquée comme étant virtuelle à l'aide du mot clé virtual. Cela permet aux classes dérivées de se substituer au comportement de la propriété à l'aide du mot clé override. Pour plus d'informations sur ces options, consultez Héritage (Guide de programmation C#).
Une propriété qui se substitue à une propriété virtuelle peut également être sealed, ce qui spécifie que pour les classes dérivées elle n'est plus virtuelle. Enfin, une propriété peut être déclarée abstract. Cela signifie qu'il n'existe aucune implémentation dans la classe et que les classes dérivées doivent écrire leur propre implémentation. Pour plus d'informations sur ces options, consultez Classes abstract et sealed et membres de classe (Guide de programmation C#).
Notes
Utiliser un modificateur virtual (référence C#), abstract (référence C#) ou override (référence C#) sur un accesseur d'une propriété statique est une erreur.
Exemple
Cet exemple illustre les propriétés d'instance, statiques et en lecture seule. Il accepte le nom de l'employé à partir du clavier, incrémente NumberOfEmployees d'une unité et affiche le nom et le matricule de l'employé.
public class Employee
{
public static int NumberOfEmployees;
private static int counter;
private string name;
// A read-write instance property:
public string Name
{
get { return name; }
set { name = value; }
}
// A read-only static property:
public static int Counter
{
get { return counter; }
}
// A Constructor:
public Employee()
{
// Calculate the employee's number:
counter = ++counter + NumberOfEmployees;
}
}
class TestEmployee
{
static void Main()
{
Employee.NumberOfEmployees = 107;
Employee e1 = new Employee();
e1.Name = "Claude Vige";
System.Console.WriteLine("Employee number: {0}", Employee.Counter);
System.Console.WriteLine("Employee name: {0}", e1.Name);
}
}
/* Output:
Employee number: 108
Employee name: Claude Vige
*/
Cet exemple illustre comment accéder à une propriété dans une classe de base masquée par une autre propriété portant le même nom dans une classe dérivée.
public class Employee
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
public class Manager : Employee
{
private string name;
// Notice the use of the new modifier:
public new string Name
{
get { return name; }
set { name = value + ", Manager"; }
}
}
class TestHiding
{
static void Main()
{
Manager m1 = new Manager();
// Derived class property.
m1.Name = "John";
// Base class property.
((Employee)m1).Name = "Mary";
System.Console.WriteLine("Name in the derived class is: {0}", m1.Name);
System.Console.WriteLine("Name in the base class is: {0}", ((Employee)m1).Name);
}
}
/* Output:
Name in the derived class is: John, Manager
Name in the base class is: Mary
*/
Points importants de l'exemple précédent :
La propriété Name dans la classe dérivée masque la propriété Name dans la classe de base. Dans ce cas, le modificateur new est utilisé dans la déclaration de la propriété dans la classe dérivée :
public new string Name
Le cast (Employee) permet d'accéder à la propriété masquée dans la classe de base :
((Employee)m1).Name = "Mary";
Pour plus d'informations sur le masquage de membres, consultez new, modificateur (référence C#).
Dans cet exemple, deux classes, Cube et Square, implémentent une classe abstraite, Shape, et substituent sa propriété abstract Area. Notez l'utilisation du modificateur override sur les propriétés. Le programme accepte l'arête comme entrée et calcule la surface du carré et du cube. Il accepte aussi la surface comme entrée et calcule l'arête correspondante du carré et du cube.
abstract class Shape
{
public abstract double Area
{
get;
set;
}
}
class Square : Shape
{
public double side;
public Square(double s) //constructor
{
side = s;
}
public override double Area
{
get
{
return side * side;
}
set
{
side = System.Math.Sqrt(value);
}
}
}
class Cube : Shape
{
public double side;
public Cube(double s)
{
side = s;
}
public override double Area
{
get
{
return 6 * side * side;
}
set
{
side = System.Math.Sqrt(value / 6);
}
}
}
class TestShapes
{
static void Main()
{
// Input the side:
System.Console.Write("Enter the side: ");
double side = double.Parse(System.Console.ReadLine());
// Compute the areas:
Square s = new Square(side);
Cube c = new Cube(side);
// Display the results:
System.Console.WriteLine("Area of the square = {0:F2}", s.Area);
System.Console.WriteLine("Area of the cube = {0:F2}", c.Area);
System.Console.WriteLine();
// Input the area:
System.Console.Write("Enter the area: ");
double area = double.Parse(System.Console.ReadLine());
// Compute the sides:
s.Area = area;
c.Area = area;
// Display the results:
System.Console.WriteLine("Side of the square = {0:F2}", s.side);
System.Console.WriteLine("Side of the cube = {0:F2}", c.side);
}
}
/* Example Output:
Enter the side: 4
Area of the square = 16.00
Area of the cube = 96.00
Enter the area: 24
Side of the square = 4.90
Side of the cube = 2.00
*/
Voir aussi
Référence
Propriétés (Guide de programmation C#)
Propriétés d'interface (Guide de programmation C#)
Propriétés implémentées automatiquement (Guide de programmation C#)