FAQ C#Consultez toutes les FAQ

Nombre d'auteurs : 39, nombre de questions : 272, dernière mise à jour : 24 mai 2015  Ajouter une question

 

Cette FAQ a été réalisée pour répondre aux questions les plus fréquemment posées concernant C# sur le forum Développement DotNET

Je tiens à souligner qu'elle ne garantit en aucun cas que les informations qu'elle contient sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Si vous trouvez une erreur, ou que vous souhaitez devenir rédacteur, lisez ceci .

Sur ce, je vous souhaite une bonne lecture.

Commentez cette FAQ : Commentez


SommaireLe langage C#Classes et membres de classe (21)
précédent sommaire suivant
 

Les types primitifs sont les "briques de base" du langage : ce sont des types de données simples, qui ne possèdent aucune donnée membre mais représentent directement une donnée. Tous ces types ont un alias en C# qui correspond à un type du .NET Framework.

Voici la liste complète des types primitifs :

Alias C# Type .NET Description
bool System.Boolean Représente une valeur vraie (true) ou fausse (false) sur 8 bits
char System.Char Représente un caractère Unicode sur 16 bits. Une séquence de caractères constitue une chaine (string)
byte System.Byte Représente un entier non signé sur 8 bits (octet), dont la valeur est comprise entre 0 et 255
sbyte System.SByte Représente un entier signé sur 8 bits, dont la valeur est comprise entre -128 et 127
short System.Int16 Représente un entier signé sur 64 bits, dont la valeur est comprise entre -32768 et 32767
ushort System.UInt16 Représente un entier non signé sur 64 bits, dont la valeur est comprise entre 0 et 65535
int System.Int32 Représente un entier signé sur 32 bits, dont la valeur est comprise entre -2147483648 et 2147483647
uint System.UInt32 Représente un entier non signé sur 32 bits, dont la valeur est comprise entre 0 et 4294967295
long System.Int64 Représente un entier signé sur 64 bits, dont la valeur est comprise entre -9223372036854775808 et 9223372036854775807
ulong System.UInt64 Représente un entier non signé sur 64 bits, dont la valeur est comprise entre 0 et 18446744073709551615
decimal System.Decimal Représente un nombre décimal sur 128 bits, dont la valeur est comprise entre 7,9E+028 et -7,9E+028 (approximativement).
La plage des valeurs possibles est moins grande qu'avec les types flottants, mais la précision est meilleure (28 chiffres significatifs),
ce qui rend le type decimal particulièrement adapté pour les calculs financiers
double System.Double Représente un nombre décimal à virgule flottante sur 64 bits (double précision), dont la valeur est comprise entre -1.79E+308 et 1.79E+308.
La précision est de 15 à 16 chiffres significatifs.
float System.Single Représente un nombre décimal à virgule flottante sur 32 bits (simple précision), dont la valeur est comprise entre -3.4E+38 et 3.4E+38.
La précision est de 7 chiffres significatifs.

Certains types primitifs numériques ont un suffixe correspondant qui permet d'indiquer le type d'une valeur litérale :

  • Aucun suffixe : int ou double (42 ou 42.0)
  • U ou u : uint (42U)
  • L ou l : long (42L)
  • UL ou ul : ulong (42UL)
  • D ou d : double (42d)
  • F ou f : float (42f)
  • M ou m : decimal (42m)

Mis à jour le 5 juillet 2010 tomlev

Les différents niveaux de visibilité pour une classe (ou structure, interface, etc.) en C# sont les suivants :

  • public : La classe est accessible à partir de n'importe quel code, y compris dans un autre assembly
  • internal : La classe n'est accessible que dans l'assembly ou elle est définie
  • protected : La classe n'est accessible qu'à partir des classes qui héritent de celle qui la contient (applicable uniquement aux classes imbriquées)
  • protected internal : La classe n'est accessible qu'à partir des classes qui héritent de celle qui la contient, et à partir du même assembly (applicable uniquement aux classes imbriquées)
  • private : La classe n'est accessible qu'a partir de la classe qui la contient (applicable uniquement aux classes imbriquées)

Si ce n'est pas précisé, une classe est par défaut :

  • interne (internal) si elle est déclarée directement dans un namespace
  • privée (private) si elle est déclarée dans une autre classe (classe imbriquée)

Mis à jour le 5 septembre 2006 dev01 tomlev

Les différents niveaux de visibilité pour les membres d'une classe (ou structure) en C# sont les suivants :

  • public : Le membre est accessible à partir de n'importe quel code, y compris dans un autre assembly
  • internal : Le membre n'est accessible qu'à partir de l'assembly courant
  • protected : Le membre n'est accessible qu'à partir des classes dérivées
  • protected internal : Le membre n'est accessible qu'à partir des classes dérivées, et à partir de l'assembly courant
  • private : Le membre n'est accessible qu'a partir de la classe qui le contient

Si ce n'est pas précisé, un membre d'une classe ou d'une structure est privé par défaut. Dans une interface ou un enum, les membres sont implicitement publics (il est d'ailleurs illégal de spécifier leur niveau d'accessibilité).

Mis à jour le 8 mars 2010 tomlev

Une propriété est un membre d'une classe (ou structure, ou interface) qui s'utilise comme un champ, mais peut implémenter sa propre logique pour accéder à la valeur. Une propriété se compose généralement de 2 accesseurs, get (pour récupérer la valeur) et set (pour la modifier).

Une propriété peut être en lecture/écriture (accesseurs get et set), en lecture seule (seulement un accesseur get), ou, plus rarement, en écriture seule (seulement un accesseur set).

Notez que selon les bonnes pratiques de Microsoft, une propriété ne doit pas effectuer de traitement lourd, et ne doit pas renvoyer un tableau. Dans ces cas-là, on utilise plutôt une méthode

Mis à jour le 5 septembre 2006 dev01 tomlev

Une propriété est définie ainsi :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class A 
{ 
    private string _maVariable; 
  
    public string MaVariable 
    { 
        get 
        { 
            return _maVariable; 
        } 
  
        set 
        { 
            _maVariable = value; 
        } 
    } 
}
Cette propriété permet d'accéder en lecture/écriture à la variable.
Pour un accès en lecture seule, il suffit de supprimer le set{ } et inversement pour un accès en écriture seule.
Notez que l'accesseur set prend implicitement un paramètre nommé value, du même type que la propriété.

En C# 3.0, il existe un "raccourci" pour déclarer une propriété qui n'implémente pas de logique particulière dans ses accesseurs. C'est ce qu'on appelle une propriété « auto-implémentée » :

Code c# : Sélectionner tout
public string MaVariable { get; set; }
Il est également possible de définir séparément le niveau d'accessibilité d'un accesseur :

Code c# : Sélectionner tout
public string MaVariable { get; private set; }
De cette façon, la propriété n'est modifiable qu'à l'intérieur de la classe.

Mis à jour le 5 septembre 2006 dev01 tomlev

Il suffit d'utiliser const devant la déclaration du champ. L'initialisation devra se faire en même temps que la déclaration car il ne sera plus possible de modifier la valeur de la variable par la suite :

Code c# : Sélectionner tout
const int maConstante = 2007;
Lorsqu'on fait référence à une constante dans le code, le compilateur remplace cette référence par la valeur de la constante.

Mis à jour le 2 janvier 2007 Jérôme Lambert tomlev

Bien que similaires, les constantes et les champs readonly sont deux choses bien différentes :

  • Une constante (const) permet de définir une valeur qui sera toujours la même, partout dans le programme et à chaque exécution
    Si vous faites référence à cette constante dans le code, le compilateur remplacera cette référence par la valeur de la constante.
    Notez que le type d'une constante ne peut être qu'un type primitif (int, bool, ulong…) ou de type string. De plus, une constante est toujours statique (c'est implicite, donc inutile de le préciser)
  • Un champ en lecture seule (readonly) est initialisé lors de la création de l'objet (ou du type si le champ est statique), et ne change plus par la suite
    On ne peut initialiser ce champ que dans le constructeur ou immédiatement lors de sa déclaration. Contrairement à une constante, un champ readonly peut être de n'importe quel type, et peut être un membre d'instance ou un membre statique.

Un champ readonly n'a pas forcément la même valeur d'un objet à l'autre, ce n'est pas une constante. Il est simplement constant après avoir été initialisé, mais on peut l'initialiser avec différentes valeurs.
Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
public class MaClasse 
{ 
    public const int MaConstante = 42; 
    public readonly string MonReadOnly; 
  
    public MaClasse(string monParam) 
    { 
        // initialisation dans le constructeur 
        MonReadOnly = monParam; 
    } 
}

Mis à jour le 1er février 2007 Jérôme Lambert tomlev

Il suffit d'utiliser this dans le header du constructeur (c'est-à-dire juste après la liste des paramètres) :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
class Employee 
{ 
    private String PrenomNom; 
  
    public Employee(String param_PrenomNom) 
    { PrenomNom = param_PrenomNom; } 
  
    public Employee(String param_Prenom, String param_Nom) 
      : this(param_Prenom + " " + param_Nom) 
    { } 
}

Mis à jour le 10 janvier 2007 Jérôme Lambert

Il suffit d'utiliser base dans le header du constructeur (c'est-à-dire juste après la liste des paramètres) :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
class Employee : Person 
{ 
    public Employee(String param_PrenomNom) 
      : base(param_PrenomNom) // passe le paramètre au constructeur de la classe Person 
    { 
    } 
}

Mis à jour le 8 mars 2010 tomlev

Une classe partielle est tout simplement une classe dont la définition est séparée dans plusieurs fichiers sources distincts. Exemple :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Fichier MaClasse.1.cs 
public partial class MaClasse 
{ 
    private List<string> infos; 
} 
  
//Fichier MaClasse.2.cs 
public partial class MaClasse 
{ 
    public MaClasse() 
    { 
        this.infos = new List<string>(); 
    } 
}
Les classes partielles sont utilisées, par exemple, par Visual Studio 2005 et SharpDevelop 2.0 pour séparer le code généré par le designer graphique du code écrit par le développeur.

Mis à jour le 10 avril 2006 dev01

Afin d'avoir une variable accessible de n'importe quel endroit de son application il faut la déclarer static.

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Configuration 
{ 
    private static string _connectionString; 
  
    public static string ConnectionString 
    { 
        get 
        { 
            return _connectionString; 
        } 
  
        set 
        { 
            _connectionString = value; 
        } 
  
    } 
}
Un membre statique appartient à un type et non à une instance d'un type, on peut donc y accéder simplement via le nom du type : Configuration.ConnectionString.

Mis à jour le 5 septembre 2006 dev01 tomlev

Il suffit de déclarer un paramètre de type tableau, en le précédant du mot réservé params. On accède ensuite aux paramètres via le tableau :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
static void Main() 
{ 
    MaFonctionVariable("Bonjour"); 
    MaFonctionVariable("Bonjour", "Au revoir"); 
} 
  
static void MaFonctionVariable(params String[] MesParams) 
{ 
    foreach (String courantString in MesParams) 
        Console.WriteLine("Valeur du paramètre : {0}", courantString); 
}

Mis à jour le 2 janvier 2007 Jérôme Lambert

Comme indiqué plus haut, on utilise le mot réservé params pour passer un nombre variable d'arguments à une fonction. Pour pouvoir passer des types différents, il suffit de déclarer le paramètre comme étant de type Object[] : étant donné que tous les types dérivent de Object, le tableau pourra contenir des objets de n'importe quel type

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
static void Main() 
{ 
    MaFonctionVariableEnType("Bonjour"); 
    MaFonctionVariableEnType("Bonjour", 2007); 
    MaFonctionVariableEnType("Bonjour", 2007, true); 
    MaFonctionVariableEnType("Bonjour", 2007, true, 10.1); 
} 
  
static void MaFonctionVariableEnType(params Object[] MesParams) 
{ 
    foreach (Object courantObject in MesParams) 
        Console.WriteLine("Valeur du paramètre : {0}", courantObject); 
}

Mis à jour le 2 janvier 2007 Jérôme Lambert tomlev

Les génériques sont une fonctionnalité apparue en C# 2.0, similaire aux templates de C++ (mais avec des différences notables). Ils permettent de définir des types ou des méthodes sans connaitre à l'avance le type de certains éléments. Cela permet d'avoir des classes ou méthodes qui offrent la même fonctionnalité pour différents types, de données, plutôt que d'avoir à redévelopper la même fonctionnalité pour chaque type.

On déclare un type ou une méthode générique en déclarant les paramètres de type entre < et >. Exemple pour une classe :

Code c# : Sélectionner tout
1
2
3
4
public class MaClasseGenerique<T> 
{ 
    public T Valeur { get; set; } 
}
Exemple pour une méthode :

Code c# : Sélectionner tout
1
2
3
4
public T GetValue<T>() 
{ 
    return (T)value; 
}
Une fois déclaré, le type générique peut être utilisé partout dans la classe ou la méthode comme n'importe quel autre type.

Pour utiliser un type ou une méthode générique, il faut remplacer le paramètre de type par le type réel qu'on souhaite utiliser :

Code c# : Sélectionner tout
1
2
3
MaClasseGenerique<int> x = new MaClasseGenerique<int>(); 
x.Valeur = 3; 
x.Valeur = "hello"; // impossible car Valeur est de type int
L'utilisation la plus fréquente des génériques est la manipulation de collections fortement typées, comme List<T> :

Code c# : Sélectionner tout
1
2
3
4
List<string> stringList = new List<string>(); 
  
stringList.Add("Salut"); // ok 
stringList.Add(1); // impossible car c'est une liste d'objets de type String

Mis à jour le 10 avril 2006 dev01 tomlev

Lorsque vous développez une classe ou une méthode générique, il est possible que vous écriviez quelque chose de ce genre :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
public class maClasse<K> 
{  
    protected K paramK; 
    public maClasse() 
    { 
        paramK = new K(); 
    } 
}

Lors de la compilation, Visual Studio vous dira qu'il est impossible de créer une instance de K. Cela est dû au fait que vous ne pouvez pas être sûr que le type K (qui sera substitué par un vrai type par la suite) possède un constructeur sans aucun paramètre.

C'est là qu'intervient le principe des contraintes sur les classes génériques. Grâce à where, il est possible de spécifier que le type K doit posséder un constructeur sans paramètre :

Code c# : Sélectionner tout
1
2
3
4
public class maClasse<K> where K : new() 
{  
    //... 
}

Il est également possible de spécifier que le type K doit hériter d'une classe ou implémenter une interface. Cela permet d'accéder aux membres définis dans la classe de base ou l'interface.

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
public class maClasse<K>    where K : new(), IDisposable 
{  
    protected K paramK; 
    public maClasse() 
    { 
        paramK = new K(); 
        paramK.Dispose(); 
    } 
}
Notez qu'il n'est pas possible de spécifier comme type de base Enum ou Delegate, c'est une limitation imposée par le compilateur.

Un dernier type de contrainte permet de spécifier que le paramètre de type doit être un type valeur (struct) ou un type référence (class) :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class maClasseReference<K> where K : class 
{ 
} 
  
public class maClasseValeur<K> where K : struct 
{ 
} 
  
// ... 
  
maClasseReference<string> ref1 = new maClasseReference<string>(); // OK, string est un type référence 
maClasseReference<int> ref2 = new maClasseReference<int>(); // impossible, int est un type valeur 
  
maClasseValeur<int> val1 = new maClasseValeur<int>(); // OK, int est un type valeur 
maClasseValeur<string> val2 = new maClasseValeur<string>(); // impossible, string est un type référence

Mis à jour le 20 mars 2007 Jérôme Lambert tomlev

Il est possible d'utiliser le mot-clé default afin de récupérer la valeur par défaut d'un type. Pour un type référence, nous récupérerons null alors que pour les types valeurs, cela dépend (0 pour int, float, etc.). Partant de ce principe, il suffit de tester la nullité de la valeur par défaut récupérée pour savoir si on a affaire à un type référence ou valeur.

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MaClasseGenerique<K> 
{ 
    public void TypeK() 
    { 
        if (default(K) != null) 
            Console.WriteLine("K est un type valeur !"); 
        else 
            Console.WriteLine("K est un type référence !"); 
    } 
} 
  
class Program 
{ 
    static void Main(string[] args) 
    { 
        (new MaClasseGenerique<int>()).TypeK(); 
        (new MaClasseGenerique<string>()).TypeK(); 
    } 
}
Une autre possibilité est d'utiliser la réflexion :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
public class MaClasseGenerique<K> 
{ 
    public void TypeK() 
    { 
        if (typeof(K).IsValueType) 
            Console.WriteLine("K est un type valeur !"); 
        else 
            Console.WriteLine("K est un type référence !"); 
    } 
}
Notez que l'usage de la réflexion peut être coûteux en termes de performance, l'utilisation de default est donc préférable. Lorsque c'est possible, l'idéal est de spécifier dans les contraintes de type générique s'il s'agit d'un type valeur ou d'un type référence (voir cette question ).

Mis à jour le 20 mars 2007 Jérôme Lambert tomlev

Il suffit de la qualifier du mot réservé sealed.

Code c# : Sélectionner tout
1
2
3
4
sealed class ClassImpossibleAHeriter 
{  
    // ... 
}

Mis à jour le 2 janvier 2007 Jérôme Lambert

L'instruction foreach permet de parcourir facilement n'importe quelle collection d'objets. Pour rendre une classe énumérable avec foreach, il suffit d'implémenter l'interface IEnumerable. Cette interface définit une seule méthode, nommée GetEnumerator, qui renvoie un objet implémentant l'interface IEnumerator.

Voici un exemple d'une classe qui peut être parcourue avec foreach et renvoie une série de nombres :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class LostNumbers : IEnumerable 
{ 
    private int[] _numbers = new[] { 4, 8, 15, 16, 23, 42 }; 
  
    public IEnumerator GetEnumerator() 
    { 
        return new LostNumbersEnumerator(_numbers); 
    } 
  
    private class LostNumbersEnumerator : IEnumerator 
    { 
        private int _index; 
        private int[] _numbers; 
  
        public LostNumbersEnumerator(int[] numbers) 
        { 
            _numbers = numbers; 
            _index = -1; 
        } 
  
        public void Reset() 
        { 
            _index = -1; 
        } 
  
        public bool MoveNext() 
        { 
            _index++; 
            return _index < _numbers.Length; 
        } 
  
        public object Current 
        { 
            get { return _numbers[_index]; } 
        } 
    } 
}
On peut maintenant utiliser la classe de la façon suivante :

Code c# : Sélectionner tout
1
2
3
4
5
LostNumbers numbers = new LostNumbers(); 
foreach (int n in numbers) 
{ 
    Console.WriteLine(n); 
}

Mis à jour le 22 août 2006 nico-pyright(c) tomlev

C# 2.0 introduit des nouveautés importantes en ce qui concerne l'énumération de collections : d'une part, les interfaces génériques IEnumerable<T> et IEnumerator<T> qui permettent d'énumérer une collection de façon fortement typée, et d'autre part les itérateurs qui permettent d'implémenter des énumérateurs beaucoup plus facilement. On crée un bloc itérateur en utilisant le mot-clé yield. Si on reprend l'exemple précédent en utilisant les fonctionnalités de C# 2.0, le code devient :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class LostNumbers : IEnumerable<int> 
{ 
    private int[] _numbers = new[] { 4, 8, 15, 16, 23, 42 }; 
  
    public IEnumerator<int> GetEnumerator() 
    { 
        for(int i = 0; i < _numbers.Length) 
        { 
            yield return _numbers[i]; 
        } 
    } 
  
    // IEnumerable<T> hérite de IEnumerable, on doit donc définir aussi la méthode 
    // non générique GetEnumerator par implémentation explicite de l'interface 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
        return this.GetEnumerator(); 
    } 
}
Le compilateur refactorise le code ci-dessus en créant une classe qui implémente IEnumerator<int> de façon à obtenir le comportement voulu.

Notez qu'il est aussi possible d'utiliser les itérateurs pour n'importe quelle méthode qui doit renvoyer une séquence d'objets :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
public IEnumerable<int> GetLostNumbers() 
{ 
    yield return 4; 
    yield return 8; 
    yield return 15; 
    yield return 16; 
    yield return 23; 
    yield return 42; 
}

Mis à jour le 8 mars 2010 tomlev

Pour rendre le code clair et facilement lisible, il est important d'appliquer une convention de nommage des identifieurs et de s'y tenir. De plus, lorsqu'on travaille en équipe, appliquer une convention commune permet de comprendre plus facilement le code écrit par d'autres.

Les conventions de nommage généralement recommandées en C# sont les suivantes :

  • Classes : Pascal case (première lettre de chaque mot en majuscule) : public class StringBuilder
  • Namespaces : Pascal case : namespace System.Text
  • Membres publics : Pascal case: public int GetHashCode()
  • Paramètres de méthode : Camel case (première lettre en majuscule, puis première lettre de chaque mot en majuscule) : int arrayIndex

Il n'y a pas vraiment de recommandations pour les membres privés et les variables locales, dans la mesure où ils relèvent de l'implémentation et ne sont pas publiquement visibles. Voici cependant l'une des conventions les plus largement utilisées :

  • Champs privés : Camel case précédé d'un underscore (_) : private List<string> _list;
  • Méthodes et propriétés privées : Pascal case : private void DoSomething()
  • Variables locales : Camel case: int currentValue;

Si ces recommandations peuvent sembler contraignantes au premier abord, sachez qu'on s'y fait très vite, et qu'elles vous faciliteront beaucoup la vie à long terme, car il deviendra beaucoup plus facile de différencier les différents types d'identifieur. Et si vous reprenez du code écrit par un d'autre développeur, vous lui serez reconnaissant d'avoir appliqué ces conventions !

Mis à jour le 5 juillet 2010 tomlev

Pour créer ses propres évènements en C#, différents « ingrédients » sont nécessaires :

Il faut tout d'abord une classe dérivée de EventArgs qui contiendra les données associées à l'évènement. Par convention, la classe s'appelle <NomDeLEvenement>EventArgs. Si l'évènement n'a pas de données associées, on utilise directement la classe EventArgs. Prenons l'exemple d'un évènement "message reçu" dans une application de messagerie :

Code c# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MessageReceivedEventArgs : EventArgs 
{ 
    private readonly string _from; 
    private readonly string _message; 
  
    public MessageReceivedEventArgs(string from, string message) 
    { 
        _from = from; 
        _message = message; 
    } 
  
    public string From 
    { 
        get { return _from; } 
    } 
  
    public string Message 
    { 
        get { return _message; } 
    } 
}
Remarquez que les propriétés de cette classe sont en lecture seule : sauf cas particulier, les gestionnaires d'un évènement ne doivent pas pouvoir en modifier les données.

On déclare également un delegate qui définit la signature des méthodes qui gèrent l'évènement. Par convention, le delegate s'appelle <NomDeLEvenement>EventHandler, le type de retour est void, le premier paramètre est de type object et correspond à l'objet qui déclenche l'évènement, et le second paramètre est l'objet qui contient les données de l'évènement :

Code c# : Sélectionner tout
public delegate void MessageReceivedEventHandler(object sender, MessageReceivedEventArgs e);
On peut aussi éviter de déclarer un delegate spécifique en utilisant le delegate générique EventHandler<TEventArgs>, où TEventArgs correspond à la classe qui contient les données de l'évènement. Si l'évènement n'a pas de données associées, on utilise généralement le delegate prédéfini EventHandler.

On déclare l'évènement proprement dit de la même façon qu'un champ dont le type est celui du delegate défini plus haut, avec le modificateur event :

Code c# : Sélectionner tout
public event MessageReceivedEventHandler MessageReceived;
Ou encore, si on utilise le delegate générique EventHandler<TEventArgs> :

Code c# : Sélectionner tout
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
Notez que, contrairement à une pratique répandue, les bonnes pratiques recommandent de ne pas
préfixer le nom de l'évènement par On (OnMessageReceived). Ce nom est généralement réservé
à un autre usage, comme on va le voir ci-dessous.
Pour finir, bien que ce ne soit pas obligatoire, on déclare généralement une méthode On<NomDeLEvenement> qui sert à déclencher l'évènement :

Code c# : Sélectionner tout
1
2
3
4
5
6
protected virtual void OnMessageReceived(string from, string message) 
{ 
    MessageReceivedEventHandler handler = MessageReceived; 
    if (handler != null) 
        handler(this, new MessageReceivedEventArgs(from, message)); 
}
Notez que l'on doit toujours s'assurer qu'il y a des gestionnaires abonnés à l'évènement, en vérifiant si le handler n'est pas null. Dans le cas contraire, tenter de déclencher l'évènement provoquerait une NullReferenceException.
Il n'y a pas de contrainte sur la signature de cette méthode, puisqu'elle n'est pas publique. En l'occurrence, il est pratique de lui passer le nom de l'expéditeur et le texte du message. Cette méthode est souvent déclarée protected virtual, de façon à ce que les classes dérivées puissent l'appeler et/ou la redéfinir ; ceci n'est pas obligatoire, il faut voir selon les cas si c'est judicieux.

Enfin, pour déclencher l'évènement, il suffit d'appeler la méthode déclarée ci-dessus :

Code c# : Sélectionner tout
OnMessageReceived("Joe", "Hello world !");

Mis à jour le 2 janvier 2011 tomlev

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2017 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

 
Responsable bénévole de la rubrique Microsoft DotNET : Hinault Romaric -