Petite évolution de C# 7.3 qui mérite notre attention, à nous fans de C#, du framework .NET et de ses apports. Microsoft a en effet apporté une attention particulière à la performance du code en mode sécurisé, à une amélioration substantielle de fonctionnalités existantes mais aussi deux nouvelles options de compilateur qui vont ravir ceux qui aiment l’opensource.
Que devons-nous retenir ?
Amélioration des performances du code sécurisé
L’indexation des champs fixed ne nécessite plus un second fixed
Vous le savez probablement, même si on en parle peu, même si on l’utilise peu, C# nous permet la création de code en mode non sécurisé. Cette écriture est très pratique pour ceux qui travaillent sur des fonctionnalités pointues où les performances sont essentielles. L’apport de C# 7.3 est de faciliter le contexte entre code sécurisé et code non-sécurisé afin que les développeurs aient justement moins accès au code non sécurisé. En effet, moins les développeurs passent de temps en code non sécurisé, plus leur code est stabilisé et sûr.
Observer par exemple dans le code ci-dessous la différence entre un code pré-C# 7.3 et un code C# 7.3. Dans cet exemple, vous devez accéder à un élément d’un tableau d’entier à l’intérieur d’une structure « unsafe »
{
public fixed int myFixedField[10];
}
//Avant c# 7.3
class Avant
{
static S s = new S();
unsafe public void MaMethod()
{
fixed (int* ptr = s.myFixedField)
{
int p = ptr[5];
}
}
}
//Apres c# 7.3
class Apres
{
static S s = new S();
unsafe public void MaMethod()
{
int p = s.myFixedField[5];
}
}
Avec C# 7.3, il n’y a plus besoin d’épingler avec fixed un pointeur complémentaire vers l’élément ; il y a a toutefois toujours besoin d’un contexte unsafe.
L’utilisation de fixed est étendue
L’instruction fixed, qui se limitait à un nombre limite de types est étendu à tout type contenant une méthode GetPinnableReference() qui retoure un ref T ou ref readonly T. L’instruction fixed est par exemple utilisable avec System.Span<T>.
Initialiseurs sur stackalloc
A l’image des initialiseurs sur les tableaux « classiques », il est possible d’utiliser la syntaxe suivante avec stackalloc (allocation d’un bloc mémoire sur la pile)
int* pArr2 = stackalloc int[] {1, 2, 3};
Span arr = stackalloc [] {1, 2, 3};
Réaffectation des variables locales ref
Très pratique, les variables locales ref peuvent être réaffectées ; ce qui était auparavant impossible.
a = ref Structure2; //réassignation
Quelques nouveautés
Comparaisons et différences sur les tuples
Tous d’abord les tuples prennent désormais en charge les comparaisons et les différences. Je vous invite vivement à lire ce document Microsoft, mais voici en résumé le comportement : les tuples peuvent se comparer grâce à une comparaison dans l’ordre des membres de gauche à ceux de droites, les comparaisons s’arrêtant dès qu’une paire n’est pas égale.
var right = (a: 5, b: 10);
Console.WriteLine(left == right); // affiche 'true'
De nombreuses choses se passent de façon transparente, notamment des conversions implicites comme dans l’exemple ci-dessous où la comparaison de int à long se fait implicitement
(int a, long b) longSecond = (5, 10);
Console.WriteLine(longFirst == longSecond); // Affiche vrai
Des conversions « lifted », grosso modo des conversions qui gère le cas des comparaisons de type Nullable s’opèrent également
(int? a, int? b) nullableMembers = (5, 10);
Console.WriteLine(left == nullableMembers); // Vrai
Les contraintes « where » sur les génériques sont améliorées
Qu’il est pratique ce « where » sur les génériques ; il permet de spécifier l’héritage mais également s’il est possible de créer une instance comme dans l’exemple suivant où le type T doit implémenter IComparable mais également avoir un constructeur accessible sans paramètre.
Vous connaissez et probablement utilisez déjà les contraintes de type struct ou class comme dans l’exemple suivant.
where T : class
where U : struct
{ }
Ils sont en revanche nouveaux grâce à C# 7.3, ce sont les contraintes de type Enum, Delegate ou MulticastDelegate .
public class UsingDelegate where T : System.Delegate { }
public class Multicaster where T : System.MulticastDelegate { }
Avec C# 7.3 est égaleemnt ajouté les types non managés, c’est à dire les type qu’on ne sont pas un type référence et ne contiennent aucun champ de type référencé à tous les niveaux d’imbrication
where T : unmanaged
{ }
Cibles d’attribut
La cible d’un attribut est l’entité à laquelle il s’applique. Les cibles peuvent être assembly, module, field, event, method, param, propery, return ou type. Il est désormais possible d’écrire :
public int Couleur { get; set; }
{ }
Nouvelles options du compilateur
Signature publique/opensource
Il est désormais possible de signer un assembly avec une clé publique grâce à
L’assembly est ainsi identifié comme « signée » (grâce à un bit dans l’assembly) mais provient d’une clé publique. Ceci permet la génération d’assembly à partir de clé publique opensource.
pathmap
L’option
contrôle le chemin des sources écrits dans les fichiers PDB ou CallerFilePathAttribute. Il est ainsi possible d’indiquer au compilateur de remplacer les chemins sources de l’environnement de build par ceux mappés.
Cet article s’est focalisé sur les améliorations les plus parlantes, la liste complète de toutes les fonctionnalités est disponible dans la documentation Microsoft.