<div class="h1">
C# S1
</div>
[TOC]
# Introduction à l'environnement .NET
:::info
**Mots clés :**
- **CLR** : Command Language Runtime
- **CLI** : Common Language Infrastructure
- **CTS** : Common Type System
- **CIL** : Common Intermediate Language
- **JIT** : Just In Time
- **API** : Application Programming Interface
:::

## CLR :
- Possède un **Ramasse miette** lors de l'exécution d'un code managé (libère la mémoire inutilisée)
- Un code **non managé** est géré par l'utilisateur
- S'assure de la **traduction du CIL** en langage machine
- Gère la **sécurité** (dépassement mémoire, accès à une ressource interdite...)
# Les bases du langage C#
*Variables : Convention Camel Case*
## Types de données et conversions
**2 types de données :**
- types primitifs
- types références (classes)

:::danger
**Conversions implicites possibles :**
double $\leftarrow$ float $\leftarrow$ long $\leftarrow$ int $\leftarrow$ short (ou char) $\leftarrow$ byte
:::
Par exemple, un float ne peut pas être converti en int
Lorsque les 2 opérandes numériques d’un opérateur binaire ne sont pas du même type, l’opérande du type le plus petit est automatiquement convertie vers le type le plus grand. Par exemple:
:::success
1.0 + 2 // équivalent à 1.0 + 2.0: 2 est converti en double
:::
### Visibilité dans les classes
:::warning
- **public** : accès ouvert pour l’extérieur et pour les classes dérivées
- **protected** : accès fermé pour l’extérieur mais ouvert pour les classes dérivées
- **private** : accès fermé pour l’extérieur et fermé pour les classes dérivées
:::
## Les tableaux
Lors de la création d’un tableau, chaque cellule du nouveau tableau est **initialisée par défaut**.
Pour connaitre la taille d’un tableau unidimentionnel on utilise la propriété **Length**
Pour connaitre la taille d’un tableau bidimentionnel on utilise la méthode **GetLength(dimension)**
Une variable de type tableau qui n’a pas été initialisée ne contient pas par défaut un tableau de taille 0.
```C#=
// Parcours d'un tableau avec foreach
using System;
int[] tab = {3,2,4,5,6};
for(int elem in tab) {
Console.WriteLine(elem);
}
```
## Les chaînes
`String` est de type **référence**
Tous les types de données peuvent être converti en chaine de caractères.
Le caractère `@` placée devant une constante de type `String` désactive l’interprétation des caractères spéciaux.
# Les classes
:::info
Type **référence**
:::
Variables d'instance = champ d'instance
Une classe n'est pas obligée de contenir des champs d'instance et des méthodes d'instance

*Représentation schématique de l'état de la mémoire du programme*
- Plusieurs variables peuvent référencer un même objet
- Si je crée trois références, elles peuvent référencer le même objet, ou non.
- L’instruction suivante n'est **pas valide** :
```C#=
Voiture v = v;
```
- Les instructions suivantes sont **valides** :
```C#=
Voiture v = new Voiture();
v=v;
```
- La déclaration de variable `A v;` ou `A` est un identificateur de classe ne provoque pas la création d’un objet de type `A`.
Exemple de la création d'une classe et de son instanciation :
```C#=
class Compteur
{
public int valeur;
public void SetValeur(int valeur)
{
this.valeur = valeur;
}
}
Compteur compteur = new Compteur();
compteur.SetValeur(10);
```
## Les constructeurs
:::danger
- Si une classe ne contient aucun constructeur, le compilateur **ajoutera automatiquement** un constructeur sans argument.
- Une classe a **toujours** un constructeur
- L'opérateur `return` ne peut pas être utilisé dans un constructeur tout comme il ne peut pas avoir de type de retour
- On constructeur ne peut pas être utilisé pour réinitialiser un objet
:::
Ordre des opérations effectuées par l'opérateur `new` :
1. **Réservation** d'une **zone physique** en mémoire pour stocker le nouvel objet
2. **Initialisation** des champs d'instance
3. Appel d'un **constructeur**
4. Retour d'une **référence** vers l'objet construit
:::info
**Initialisation par défaut**
Numérique : `0`
Booléen : `false`
Référence : `null`
:::
### Chaînage des constructeurs
Se fait lorsqu'une classe contient plusieurs constructeurs. On utilise le terme `this`
```C#=
class Cercle
{
public int x;
public int y;
public Cercle() : this(0, 0)
// Le constructeur sans argument est chaîné avec le constructeur paramétrique
{ } // tout est fait par l'autre constructeur
public Cercle(int x, int y) // constructeur paramétrique
{
this.x = x ;
this.y = y ;
}
}
```
## Encapsulation
:::info
Consiste à choisir les éléments que l’on laisse apparent pour l’utilisateur (*interface*) et ceux que l’on cache. Avantages :
- Utilisabilité
- Souplesse
- Fiabilité
- Clareté du code
:::
**Qualificateurs :**
- *public* (accessible de n'importe où)
- *private*, par défaut (accessible seulement depuis la classe)
- *protected* (accessible depuis la classe et ses enfants)
Les seuls membres privés auxquels je peux accéder sont ceux de l'instance courante this et ceux statique de la classe
:::warning
Les règles de visibilité sont vérifiées à la **compilation**
:::
## Les propriétés
```C#=
Visibilite TypeDeDonnees IdentificateurDePropriete {
get { //On peut mettre le getter en private (private get {...]})
...
return valeurDeLaPropriete;
}
set { //On peut mettre le setter en private (private set {...]})
... = value;
}
}
```
Syntaxe d'une **propriété auto-implémentée** (n'est pas associée à un champ, la propriété se comporte en quelque sorte comme sa propre variable):
```C#=
public double Prix { get ; private set ; }
// propriété auto-implémentée avec modificateur privé
Prix = 10;
```
:::info
- Une propriété peut être déclarée **sans getter ou setter**
- Elle n'est pas forcément associée à un champ
- **Convention** : même nom pour la propriété et le champ privé associé (avec une majuscule pour la propriété)
:::
## Membres statiques
*(Ou membre de classe)*
```C#=
class A
{
double valeur;
public static int compteur = 0; // nombre d'objets de type A créés
public A(double valeur){
this.valeur = valeur;
A.compteur++; // on vient de créer un nouvel objet
}
public static void Test(){ // une méthode statique
A a1 = new A(3.1);
WriteLine(A.compteur); // 1
A a2 = new A(3.2);
WriteLine(A.compteur); // 2
WriteLine(a1.valeur);
// 3.1 accès à un champ d'instance à partir d'une référence
//WriteLine(this.valeur);
//ERREUR la référence this n'est pas défini dans une méthode statique
//WriteLine(a1.compteur);
//ERREUR accès à partir une référence à un champ statique
}
}
```
Le terme `this` ne peut pas être utilisé dans une méthode statique
Un champ d'instance ne peut pas être accessible depuis une méthode statique
On ne peut pas initialiser un champ statique en utilisant les valeurs des champs d'instances
:::info
**Un membre statique peut être appelé de deux façon :**
- *NomDeLaClasse.membreStatique*
- *membreStatique* (le compilateur ajoutera automatiquement le nom de la classe devant)
Le mot **statique** est associé à tout ce qui est calculé au moment de la **compilation**.
Son opposé est le mot **dynamique** qui désigne ce qui est calculé pendant **l’exécution du programme**.
:::
## Polymorphisme
La signature d'une fonction correspond à son nom auquel s'ajoute les types de ses paramètres, dans l'ordre.
:::success
- `int uneFonction(int a, double b)` et `float uneFonction(int a, double b)` ont les mêmes signatures même si leur type de retour est différent
- `int uneFonction(int a, double b)` et `int uneFonction(double a, int b)` n'ont pas les mêmes signatures (ordre des types de paramètres différents).
- `int uneFonction(int a)` et `int uneFonction(double a)` n'ont pas la même signature (type des paramètres différent)
- `int uneFonction(int a)` et `int uneFonction(int a, double b)` n'ont pas la même signature (nombre de paramètres différent)
:::
:::warning
Si aucune signature ne correspond aux paramètres passés lors de l'appel de fonction, le compilateur essaye de trouver une fonction qui s'en rapproche (par exemple en transformant un`int` en `double`)
:::
## Héritage
```C#
class IdentificateurClasse : IdentificateurClasseParent
{
}
```
:::danger
Une classe fille hérite de **tous** les attributs de la classe parent, même si elle ne peut pas y accéder.
Pour accéder à un membre d'une classe avec l'opérateur `.` sans cast, le compilateur utilise le type déclaré à l'initialisation de la variable.
:::
### Polymorphisme d'héritage
Il est possible de redéfinir des méthodes de la classe mère dans la classe fille à l'aide du mot clé `override`
```C#
public override Type nomFonction(args...) {
// Contenu de la fonction redéfinie
}
```
:::success
Exemple d'héritage avec redéfinition de méthode
```C#
public class A {
public int f(int a) {
return a;
}
}
public class B : A {
public override int f(int a) {
return a+1;
}
}
```
:::
:::danger
Une méthode redéfinie est un polymorphisme d'héritage (et non un héritage ou une définition de méthode).
Une méthode portant la même signature qu'une méthode de sa classe parent A et qui ne comporte pas le mot clé `override` crée ce que l'on appelle un **masquage** (la fonction originelle n'est plus accessible). La méthode de la classe courante B est ignorée, et on ne garde que celle de la classe parent A. Ceci est valide notamment quand le type déclaré est celui de la classe parent A et le type constaté celui de la classe courante B. Si les types déclarés et constatés sont les mêmes (ex:B), on garde la méthode de la classe B.
:::
### Chainage des constructeurs
```C#=
class A{
public A(){}:
}
class B : A{
public B() : base()
// chainage avec le constructeur sans argument de A
{}
}
```
:::warning
- Si je ne chaine pas un constructeur vers un constucteur de la classe mère alors les attributs hérités ne seront pas initialisés par défaut.
- Un constructeur de la classe mère est toujours exécuté avant l’exécution d’un constructeur de la classe fille.
- Si on ne chaîne pas explicitement un constructeur de B, le compilateur génèrera automatiquement un chainage implicite avec le constructeur sans argument de la classe parent. Si la classe parent ne possède pas de constructeur sans argument cela génèrera une erreur de compilation.
:::
### Chainage des méthodes
Une méthode héritée peut appeler la méthode de la classe parent avec le mot clé `base`.
:::success
```C#=
class Cabriolet : Voiture
{
public override void TestAllumage()
{
base.TestAllumage();
// Méthode de la classe Voiture
TestToitAmovible();
// Methode de la classe Cabriolet
}
}
```
:::
### Classes abstraites
Une classe abstraite ne peut pas être instanciée. Les classes filles héritant d'une classe abstraite n'héritent pas de ses méthodes abstraites, mais peuvent les redéfinir (avec le mot clé `override`).
Une méthode abstraite ne contient pas de corps. Une classe doit être abstraite (avec le mot clé `abstract`) pour contenir au moins une méthode abstraite
:::success
```C#
abstract class Shape
{
protected string nom ;
public abstract void Draw() ;
}
class Triangle : Shape
{
protected Point p1, p2, p3 ;
public override void Draw() {
// Redéfinition de la méthode Draw();
}
}
```
:::
# Compléments de langage
## Exceptions
Deux sources d'exceptions :
- Causées par un bug du programme
- Causée volontairement par le programmeur
```C#=
double Division(int a, int b){
if(b==0)
throw new AritmeticException("Erreur : Division par 0.");
return a/b;
}
static void main(String[] args){
try {
Division(2,0);
}
catch (AritmeticException e){
Console.WriteLine("Erreur sur une opération arithmétique!", e.Message);
}
catch (Exception){
Console.WriteLine("Erreur!");
}
finally {
Console.WriteLine("Dans tous les cas on passe ici!");
}
}
```
:::info
On peut avoir un bloc **try** et **finally** sans bloc **catch**
:::
## Enumérations
```C#=
enum EtatCivil {Celibataire, Marie, Divorce, Veuf} // définition du type EtatCivil
...
EtatCivil ec ; // définition d’une variable de type EtatCivil
ec = EtatCivil.Marie ; // modification de la valeur
```