« utilisation basée sur des modèles » et « utilisation de déclarations »
Remarque
Cet article est une spécification de fonctionnalité. La spécification sert de document de conception pour la fonctionnalité. Il inclut les modifications de spécification proposées, ainsi que les informations nécessaires pendant la conception et le développement de la fonctionnalité. Ces articles sont publiés jusqu’à ce que les modifications de spécification proposées soient finalisées et incorporées dans la spécification ECMA actuelle.
Il peut y avoir des différences entre la spécification de la fonctionnalité et l’implémentation terminée. Ces différences sont consignées dans les notes pertinentes de la réunion de conception linguistique (LDM).
Vous pouvez en savoir plus sur le processus d’adoption des speclets de fonctionnalités dans la norme de langage C# dans l’article sur les spécifications .
Résumé
Le langage ajoute deux nouvelles fonctionnalités autour de l’instruction using
afin de simplifier la gestion des ressources : using
doit reconnaître un modèle jetable en plus de IDisposable
et ajouter une déclaration de using
à la langue.
Motivation
La déclaration using
est un outil efficace pour la gestion des ressources aujourd’hui, mais elle nécessite un peu de cérémonie. Les méthodes qui ont plusieurs ressources à gérer peuvent être encombrées syntaxiquement avec une série d’instructions using
. Cette charge syntaxique est suffisamment importante pour que la plupart des lignes directrices relatives au style de codage prévoient explicitement une exception concernant les accolades pour ce scénario.
La déclaration using
élimine une grande partie de la formalité ici et met C# au niveau des autres langages qui incluent des blocs de gestion des ressources. En outre, le using
basé sur des modèles permet aux développeurs d’étendre l’ensemble des types qui peuvent participer ici. Dans de nombreux cas, la suppression de la nécessité de créer des types wrapper qui existent uniquement pour autoriser une utilisation de valeurs dans une instruction using
.
Ensemble, ces fonctionnalités permettent aux développeurs de simplifier et d’étendre les scénarios où using
peuvent être appliqués.
Conception détaillée
utilisation d'une déclaration
La langue permet d’ajouter using
à une déclaration de variable locale. Une telle déclaration aura le même effet que la déclaration de la variable dans une instruction using
au même emplacement.
if (...)
{
using FileStream f = new FileStream(@"C:\users\jaredpar\using.md");
// statements
}
// Equivalent to
if (...)
{
using (FileStream f = new FileStream(@"C:\users\jaredpar\using.md"))
{
// statements
}
}
La durée de vie d'un local using
s'étendra jusqu'à la fin de l'étendue dans laquelle il est déclaré. Les variables locales using
seront ensuite supprimées dans l'ordre inverse dans lequel elles sont déclarées.
{
using var f1 = new FileStream("...");
using var f2 = new FileStream("...");
using var f3 = new FileStream("...");
...
// Dispose f3
// Dispose f2
// Dispose f1
}
Il n'y a pas de restrictions autour de goto
, ou de toute autre construction de flux de contrôle face à une déclaration using
. Au lieu de cela, le code agit comme il le ferait pour l’instruction using
équivalente :
{
using var f1 = new FileStream("...");
target:
using var f2 = new FileStream("...");
if (someCondition)
{
// Causes f2 to be disposed but has no effect on f1
goto target;
}
}
Une variable locale déclarée dans une déclaration locale using
sera implicitement en lecture seule. Cela correspond au comportement des locales déclarées dans une instruction using
.
La grammaire du langage pour les déclarations using
est la suivante :
local-using-declaration:
'using' type using-declarators
using-declarators:
using-declarator
using-declarators , using-declarator
using-declarator:
identifier = expression
Restrictions relatives à la déclaration using
:
- Peut ne pas apparaître directement à l’intérieur d’une étiquette de
case
, mais doit se trouver dans un bloc à l’intérieur de l’étiquettecase
. - Peut ne pas apparaître dans le cadre d’une déclaration de variable
out
. - Doit avoir un initialiseur pour chaque déclarateur.
- Le type local doit être implicitement convertible en
IDisposable
ou remplir le modèle deusing
.
utilisation basée sur un modèle
Le langage ajoute la notion d’un modèle jetable pour les types ref struct
: il s’agit d’un ref struct
qui a une méthode d’instance Dispose
accessible. Les types qui correspondent au modèle jetable peuvent participer à une instruction ou à une déclaration using
sans être obligés d'implémenter IDisposable
.
ref struct Resource
{
public void Dispose() { ... }
}
using (var r = new Resource())
{
// statements
}
Cela permettra aux développeurs de tirer parti de using
pour les types ref struct
. Ces types ne peuvent pas implémenter d’interfaces en C# 8 et ne peuvent donc pas participer à des instructions using
.
Les mêmes restrictions d’une instruction using
traditionnelle s’appliquent ici également : les variables locales déclarées dans l'using
sont en lecture seule, une valeur null
n’entraîne pas la levée d’une exception, etc. La génération de code sera différente uniquement dans le cas où il n’y aura pas de cast en IDisposable
avant d’appeler Dispose :
{
Resource r = new Resource();
try {
// statements
}
finally {
if (r != null) r.Dispose();
}
}
Pour ajuster le modèle jetable, la méthode Dispose
doit être un membre d’instance accessible, sans paramètre et avoir un type de retour void
. Il ne peut pas s’agir d’une méthode d’extension.
Considérations
Aucune de ces considérations n’a été mise en œuvre en C# 8
étiquettes de cas sans blocs
Un using declaration
est illégal directement à l'intérieur d'une étiquette case
en raison des complications liées à sa durée de vie réelle. Une solution potentielle consiste simplement à lui donner la même durée de vie qu’une out var
dans le même emplacement. Il a été jugé que la complexité supplémentaire de l'implémentation de la fonctionnalité et la facilité de contournement (il suffit d'ajouter un bloc à l'étiquette case
) ne justifient pas de suivre cette voie.
Extensions futures
Locales fixes
Une instruction fixed
possède toutes les propriétés des instructions using
qui ont motivé la possibilité d'avoir des éléments locaux using
. Il conviendrait d'envisager d'étendre cette fonctionnalité aux locals fixed
. Les règles de durée de vie et de classement doivent s’appliquer de la même manière pour using
et fixed
ici.
C# feature specifications