"uso basato su modelli" e "dichiarazioni using"
Nota
Questo articolo è una specifica delle funzionalità. La specifica funge da documento di progettazione per la funzionalità. Include le modifiche specifiche proposte, insieme alle informazioni necessarie durante la progettazione e lo sviluppo della funzionalità. Questi articoli vengono pubblicati fino a quando le modifiche specifiche proposte non vengono completate e incorporate nella specifica ECMA corrente.
Potrebbero verificarsi alcune discrepanze tra la specifica di funzionalità e l'implementazione completata. Tali differenze vengono acquisite nelle note
Altre informazioni sul processo di adozione delle speclette di funzionalità nello standard del linguaggio C# sono disponibili nell'articolo sulle specifiche .
Problema del campione: https://github.com/dotnet/csharplang/issues/114
Sommario
Il linguaggio aggiungerà due nuove funzionalità relative all'istruzione using
per semplificare la gestione delle risorse: using
deve riconoscere un modello eliminabile oltre a IDisposable
e aggiungere una dichiarazione di using
al linguaggio.
Motivazione
La dichiarazione using
è uno strumento efficace per la gestione delle risorse oggi, ma richiede un po ' di cerimonia. I metodi che hanno un certo numero di risorse da gestire possono incagliarsi sintatticamente con una serie di istruzioni using
. Questo onere sintattico è tale che la maggior parte delle linee guida di stile di codifica prevede esplicitamente un'eccezione per le parentesi graffe in questo scenario.
La dichiarazione di using
rimuove molta della complessità qui e porta C# al livello di altri linguaggi che includono blocchi di gestione delle risorse. Inoltre, la using
basata su modelli consente agli sviluppatori di espandere il set di tipi che possono partecipare qui. In molti casi, si elimina la necessità di creare tipi wrapper che esistono solo per consentire l'utilizzo di valori in un'istruzione using
.
Insieme queste funzionalità consentono agli sviluppatori di semplificare ed espandere gli scenari in cui è possibile applicare using
.
Progettazione dettagliata
dichiarazione using
La lingua consentirà di aggiungere using
a una dichiarazione di variabile locale. Tale dichiarazione avrà lo stesso effetto della dichiarazione della variabile in un'istruzione using
nella stessa posizione.
if (...)
{
using FileStream f = new FileStream(@"C:\source\using.md");
// statements
}
// Equivalent to
if (...)
{
using (FileStream f = new FileStream(@"C:\source\using.md"))
{
// statements
}
}
La durata di un using
locale si estenderà fino alla fine del contesto in cui viene dichiarato. I using
locali verranno quindi eliminati nell'ordine inverso in cui sono dichiarati.
{
using var f1 = new FileStream("...");
using var f2 = new FileStream("...");
using var f3 = new FileStream("...");
...
// Dispose f3
// Dispose f2
// Dispose f1
}
Non esistono restrizioni per goto
o per qualsiasi altro costrutto di flusso di controllo in presenza di una dichiarazione di using
. Al contrario, il codice agisce esattamente come per l'istruzione using
equivalente:
{
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;
}
}
Una variabile dichiarata in una dichiarazione locale using
sarà implicitamente di sola lettura. Questo corrisponde al comportamento delle variabili locali dichiarate in un'istruzione using
.
La grammatica per le dichiarazioni di using
sarà la seguente:
local-using-declaration:
'using' type using-declarators
using-declarators:
using-declarator
using-declarators , using-declarator
using-declarator:
identifier = expression
Restrizioni relative alla dichiarazione di using
:
- Potrebbe non apparire direttamente all'interno di un'etichetta
case
, ma deve trovarsi in un blocco all'interno dell'etichettacase
. - Non può comparire come parte di una dichiarazione di variabile
out
. - Deve avere un inizializzatore per ogni dichiaratore.
- Il tipo locale deve essere convertibile in modo implicito in
IDisposable
o soddisfare il modello diusing
.
basato su modelli tramite
Il linguaggio aggiungerà il concetto di modello eliminabile per i tipi ref struct
, ovvero un ref struct
che ha un metodo di istanza Dispose
accessibile. I tipi che soddisfano il modello eliminabile possono partecipare a un'istruzione o a una dichiarazione using
senza dover implementare IDisposable
.
ref struct Resource
{
public void Dispose() { ... }
}
using (var r = new Resource())
{
// statements
}
In questo modo gli sviluppatori potranno sfruttare using
per i tipi di ref struct
. Questi tipi non possono implementare interfacce in C# 8 e quindi non possono partecipare a istruzioni using
.
Le stesse restrizioni di un'istruzione using
tradizionale si applicano anche qui: le variabili locali dichiarate nel using
sono di sola lettura, un valore null
non causerà la generazione di un'eccezione e così via... La generazione del codice sarà diversa solo perché non verrà eseguito un cast per IDisposable
prima di chiamare Dispose:
{
Resource r = new Resource();
try {
// statements
}
finally {
if (r != null) r.Dispose();
}
}
Per adattare il modello eliminabile, il metodo Dispose
deve essere un membro dell'istanza accessibile, senza parametri, e avere un tipo di ritorno void
. Non può essere un metodo di estensione.
Considerazioni
Nessuna di queste considerazioni è stata implementata in C# 8
etichette case senza blocchi
Un using declaration
è illegale direttamente all'interno di un'etichetta case
a causa di complicazioni legate alla sua durata effettiva. Una possibile soluzione consiste semplicemente nel dare ad esso la stessa durata di un out var
nella stessa posizione. È stato ritenuto che la complessità aggiuntiva per l'implementazione della funzionalità e la facilità della soluzione alternativa (aggiungere solo un blocco all'etichetta case
) non giustificassero l'adozione di questo percorso.
Espansioni Future
variabili locali fisse
Un'istruzione fixed
ha tutte le proprietà delle istruzioni using
che hanno portato alla possibilità di avere variabili locali using
. È consigliabile considerare l'estensione di questa funzionalità anche a fixed
locali. Le regole relative alla durata e all'ordinamento dovrebbero essere applicate equamente per using
e fixed
qui.
C# feature specifications