Annotazioni dei parametri di tipo non vincolato
Nota
Questo articolo è una specifica di 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 pertinenti del language design meeting (LDM) .
Altre informazioni sul processo per l'adozione di speclet di funzionalità nello standard del linguaggio C# sono disponibili nell'articolo sulle specifiche di .
Problema del campione: https://github.com/dotnet/csharplang/issues/3297
Sommario
Consenti annotazioni di nullabilità per i parametri di tipo che non sono vincolati ai tipi di valore o ai tipi di riferimento: T?
.
static T? FirstOrDefault<T>(this IEnumerable<T> collection) { ... }
?
annotazione
In C#8 le annotazioni ?
possono essere applicate solo ai parametri di tipo vincolati in modo esplicito ai tipi valore o ai tipi riferimento.
In C#9 ?
annotazioni possono essere applicate a qualsiasi parametro di tipo, indipendentemente dai vincoli.
A meno che un parametro di tipo non sia vincolato in modo esplicito ai tipi valore, le annotazioni possono essere applicate solo all'interno di un contesto di #nullable enable
.
Se un parametro di tipo T
viene sostituito con un tipo riferimento, T?
rappresenta un'istanza nullable di tale tipo di riferimento.
var s1 = new string[0].FirstOrDefault(); // string? s1
var s2 = new string?[0].FirstOrDefault(); // string? s2
Se T
viene sostituito con un tipo valore, T?
rappresenta un'istanza di T
.
var i1 = new int[0].FirstOrDefault(); // int i1
var i2 = new int?[0].FirstOrDefault(); // int? i2
Se T
viene sostituito con un tipo con annotazioni U?
, T?
rappresenta il tipo annotato U?
anziché U??
.
var u1 = new U[0].FirstOrDefault(); // U? u1
var u2 = new U?[0].FirstOrDefault(); // U? u2
Se T
viene sostituito con un tipo U
, T?
rappresenta U?
, anche all'interno di un contesto di #nullable disable
.
#nullable disable
var u3 = new U[0].FirstOrDefault(); // U? u3
Per i valori restituiti, T?
equivale a [MaybeNull]T
; per i valori degli argomenti, T?
equivale a [AllowNull]T
.
L'equivalenza è importante quando si esegue l'override o l'implementazione di interfacce da un assembly compilato con C#8.
public abstract class A
{
[return: MaybeNull] public abstract T F1<T>();
public abstract void F2<T>([AllowNull] T t);
}
public class B : A
{
public override T? F1<T>() where T : default { ... } // matches A.F1<T>()
public override void F2<T>(T? t) where T : default { ... } // matches A.F2<T>()
}
vincolo default
Per compatibilità con il codice esistente in cui i metodi generici sottoposti a override e implementati in modo esplicito non possono includere clausole di vincolo esplicite, T?
in un metodo sottoposto a override o implementato in modo esplicito viene considerato come Nullable<T>
in cui T
è un tipo valore.
Per consentire annotazioni per i parametri di tipo vincolati ai tipi di riferimento, C#8 ha permesso esplicitamente i vincoli where T : class
e where T : struct
sul metodo sovrascritto o implementato in modo esplicito.
class A1
{
public virtual void F1<T>(T? t) where T : struct { }
public virtual void F1<T>(T? t) where T : class { }
}
class B1 : A1
{
public override void F1<T>(T? t) /*where T : struct*/ { }
public override void F1<T>(T? t) where T : class { }
}
Per consentire annotazioni per i parametri di tipo non vincolati ai tipi di riferimento o ai tipi valore, C#9 consente un nuovo vincolo where T : default
.
class A2
{
public virtual void F2<T>(T? t) where T : struct { }
public virtual void F2<T>(T? t) { }
}
class B2 : A2
{
public override void F2<T>(T? t) /*where T : struct*/ { }
public override void F2<T>(T? t) where T : default { }
}
È un errore usare un vincolo di default
diverso da un override del metodo o un'implementazione esplicita.
È un errore usare un vincolo default
quando il parametro di tipo corrispondente nel metodo di interfaccia o sottoposto a override è vincolato a un tipo riferimento o a un tipo valore.
Riunioni di progettazione
C# feature specifications