Ce qui est cool dans C# 8 et .NET Core 3 – Visual Studio Magazine

.NET pratique

Ce qui est cool dans C# 8 et .NET Core 3

Vous manquez certaines fonctionnalités intéressantes si vous créez des applications dans .NET Core 3 et que vous n’exploitez pas les nouvelles fonctionnalités de C# 8. Voici ce que Peter pense être celles que vous trouverez les plus utiles.

L’une des meilleures choses à propos de .NET Core 3.x est C # 8. Voici une liste des choses que je pense au moins que vous devriez exploiter si vous travaillez en C # 8 ou version ultérieure (je dirai simplement ” C# 8″ à partir de maintenant). Juste pour être méchant, j’ai gardé celui que je pense utiliser le plus pour la fin.

Étendre les interfaces sans douleur
Disons que vous avez une interface pour vous assurer que les classes ont des propriétés FirstName et LastName plus une méthode appelée InitializeNames pour définir ces propriétés :

public interface IName
{
  public string FirstName {get; set; }
  public string LastName {get; set; }
  public void InitializeNames(string FullName);
}

Quelqu’un ajoute cette interface à sa classe Customer parce qu’il veut que la classe Customer fonctionne avec toutes les parties de l’application qui comptent sur des objets ayant ces trois membres :

public class Customer : IName
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public void InitializeNames(string FullName) 
  {
    //…implementation omitted…
  }
}

Immédiatement, vous commencez à recevoir des plaintes de certains développeurs (pas tous) car ils ont du mal à implémenter une méthode InitializeNames fiable qui n’accepte qu’un seul paramètre. Ils veulent une version de la méthode qui accepte deux paramètres : prénom et nom.

Vous pouvez simplement ajouter un nouveau membre à l’interface IName. Malheureusement, cela va créer du chagrin pour tous les développeurs qui ont déjà utilisé l’interface (le développeur qui a créé cette classe de clients, par exemple). Lorsque ces développeurs recompileront leur application avec la nouvelle définition IName, ils devront écrire une nouvelle implémentation pour prendre en charge la nouvelle méthode – une méthode dont ils ne voulaient même pas.

La solution consiste à ajouter le nouveau membre InitializeNames à l’interface mais aussi à lui donner une implémentation par défaut. L’interface améliorée ressemble maintenant à ceci :

public interface IName
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public void InitializeNames(string FullName);
  public void InitializeNames(string FirstName, string LastName) 
  {
    this.FirstName = FirstName;
    this.LastName = LastName;
  }
}

Les applications existantes utilisant la version d’origine de l’interface n’ont pas à fournir d’implémentation pour la nouvelle version de InitializeNames — leur code continuera à la fois à se construire et à s’exécuter.

Cela s’améliore : si j’utilise l’une de ces classes “non améliorées” et que je souhaite profiter de l’implémentation par défaut, je peux : je n’ai qu’à déclarer ma variable en utilisant le nom de l’interface. En déclarant la variable qui contient mon objet Customer comme IName, par exemple, je peux appeler l’implémentation par défaut avec un code comme celui-ci :

IName cust = new Customer();
cust.InitializeNames("Peter", "Vogel");

Accéder aux collections
Nous tenons tous pour acquis que nous pouvons accéder au premier, deuxième, troisième, etc. élément d’une collection en fournissant une position, en comptant depuis le début de la collection. Cet exemple accède au premier élément de la collection :

Customer cust = custs[0];

En C# 8, vous pouvez désormais également compter à rebours à partir de la fin de la collection en plaçant un circonflexe (^) devant votre numéro de position. Ce code obtient le dernier élément d’une collection :

Customer cust = custs[^1];

Ne pas utiliser [^0]le chemin – c’est la même chose que ce code et il n’y a rien là-bas donc votre code va exploser:

Customer cust = custs[custs.Count()];

Cela signifie que je peux implémenter la version à paramètre unique de InitializeNames avec un code comme celui-ci :

public void InitializeNames(string FullName) 
{
  string[] Names = FullName.Split(" ");
  FirstName = Names[0];
  LastName = Names[^1];
}

Mais attendez, il y a plus : vous pouvez désormais spécifier une plage entre crochets en fournissant une position de début et une position de fin unique, séparées par deux points. Comme l’implique cette syntaxe alambiquée, la position à gauche des deux points (le début de la plage) est incluse dans la plage mais la position à droite est la position juste après le dernier élément inclus dans la plage. Cela signifie, par exemple, que la gamme [0..^0] spécifie le tableau entier du premier élément au dernier, même si vous ne pouvez pas utiliser ^0 seul. Dactylographie [0..^0] est plus de travail que nécessaire, cependant : si vous voulez spécifier la première ou la dernière position dans la collection, vous pouvez simplement omettre le numéro de position de ce côté des points. Ainsi, en utilisant [..] car votre gamme spécifie toute la collection.

Ce code copie tous les éléments des positions 0 à 2 du tableau Names dans le tableau FirstPart (rappelez-vous : la position à droite est une au-delà du dernier élément de la plage) :

string[] FirstPart = names[..3];

Vous n’avez pas besoin de spécifier les positions de votre code dans une plage – vous pouvez utiliser des variables pour l’une ou l’autre position. Il existe même un nouveau type de variable que vous pouvez utiliser pour conserver une plage. Cela s’appelle (évidemment) Range, et vous permet de stocker une plage à utiliser plus tard.

Voici un exemple qui construit une plage, puis l’utilise pour copier une partie d’une collection dans une autre collection :

int left = 0;
int right = 2;
Range nameRange = left..right;
string[] FirstPart = names[nameRange];

Nettoyer après soi
Si vous voyez qu’une classe a implémenté l’interface IDisposable (si la classe a une méthode Dispose), vous devez appeler cette méthode Dispose. Les développeurs ajoutent la méthode Dispose à leurs objets pour vous signaler qu’il y a du code de nettoyage associé à la classe (ce code sera soit dans la méthode Dispose soit appelé depuis celle-ci).

Jusqu’à C# 8, vous pouviez déclarer vos variables avec un using block, qui garantit que l’objet dans la variable aura sa méthode Dispose appelée à la fin du bloc. La grande majorité du temps, cela signifiait que vous deviez configurer votre using bloc en haut de votre méthode et fermez-le en bas de votre méthode.

Avec C# 8, ce code typique devient beaucoup plus simple : il suffit de déclarer la variable contenant l’objet avec le using mot-clé et la méthode Dispose de votre objet seront appelées automatiquement lorsque cette variable sortira de la portée. Ce code le fait avec mon objet Customer pour s’assurer que la méthode Dispose de l’objet est appelée lorsque la méthode InitCustomer se termine :

private void InitCustomer(string CustName)
{
  using Customer cust = new Customer();
  cust.InitializeNames(custName);
  //…rest of method omitted…
}

Vraiment, il y a un cas à faire que vous devriez ajouter using à toutes vos déclarations de variable si vous initialisez également la variable avec un objet (et, bien sûr, puis supprimez le using mot-clé lorsque le compilateur vous indique que la classe n’implémente pas IDisposable).

Et, au fait, il y a maintenant une interface IAsyncDisposable. Si vous ajoutez du code de nettoyage à votre classe et que vous pouvez effectuer ce nettoyage de manière asynchrone, c’est l’interface que vous devez ajouter à votre classe. Si vous travaillez avec une classe qui implémente l’interface IAsyncDisposable, utilisez simplement le await mot-clé avec le using mot-clé, comme celui-ci (ou si vous ajoutez using et le compilateur se plaint :

private async void InitCustomer(string CustName)
{
  await using Customer cust = new Customer();

Gagnant : nouvelle fonctionnalité la plus utilisée
Des modèles de propriété ont également été ajoutés en C # 8, qui ont suffisamment de ramifications pour mériter leur propre publication. Au lieu de cela, je vais finir avec le C# 8 ??= opérateur qui affecte une valeur à une variable … mais uniquement si cette variable est définie sur null. Donc, si vous avez écrit

if (cust == null)
{
  cust = new Customer();
}

Vous pouvez maintenant simplement écrire ceci :

cust ??= new Customer();

Et, de toutes ces fonctionnalités, c’est peut-être la fonctionnalité C# 8 que j’utilise le plus.

A propos de l’auteur

Peter Vogel est architecte système et responsable des services d’information PH&V. PH&V fournit des conseils complets, de la conception UX à la modélisation d’objets en passant par la conception de bases de données. Peter tweete à propos de ses chroniques VSM avec le hashtag #vogelarticles. Ses articles de blog sur la conception de l’expérience utilisateur sont disponibles à l’adresse http://blog.learningtree.com/tag/ui/.

.

Leave a Comment