Obegränsade typparameterannoteringar
Anmärkning
Den här artikeln är en funktionsspecifikation. Specifikationen fungerar som designdokument för funktionen. Den innehåller föreslagna specifikationsändringar, tillsammans med information som behövs under utformningen och utvecklingen av funktionen. Dessa artiklar publiceras tills de föreslagna specifikationsändringarna har slutförts och införlivats i den aktuella ECMA-specifikationen.
Det kan finnas vissa skillnader mellan funktionsspecifikationen och den slutförda implementeringen. Dessa skillnader samlas in i de relevanta anteckningarna från Language Design Meeting (LDM).
Du kan läsa mer om processen för att införa funktionsspecifikationer i C#-språkstandarden i artikeln om specifikationerna.
Champion-problem: https://github.com/dotnet/csharplang/issues/3297
Sammanfattning
Tillåt null-anteckningar för typparametrar som inte är begränsade till värdetyper eller referenstyper: T?
.
static T? FirstOrDefault<T>(this IEnumerable<T> collection) { ... }
?
kommentar
I C#8 kunde ?
anteckningar endast tillämpas på typparametrar som uttryckligen var begränsade till värdetyper eller referenstyper.
I C#9 kan ?
anteckningar tillämpas på valfri typparameter, oavsett begränsningar.
Såvida inte en typparameter uttryckligen är begränsad till värdetyper kan anteckningar endast tillämpas inom en #nullable enable
kontext.
Om en typparameter T
ersätts med en referenstyp representerar T?
en nullbar instans av den referenstypen.
var s1 = new string[0].FirstOrDefault(); // string? s1
var s2 = new string?[0].FirstOrDefault(); // string? s2
Om T
ersätts med en värdetyp representerar T?
en instans av T
.
var i1 = new int[0].FirstOrDefault(); // int i1
var i2 = new int?[0].FirstOrDefault(); // int? i2
Om T
ersätts med en kommenterad typ U?
representerar T?
den kommenterade typen U?
i stället för U??
.
var u1 = new U[0].FirstOrDefault(); // U? u1
var u2 = new U?[0].FirstOrDefault(); // U? u2
Om T
ersätts med en typ U
representerar T?
U?
, även inom en #nullable disable
kontext.
#nullable disable
var u3 = new U[0].FirstOrDefault(); // U? u3
För returvärden motsvarar T?
[MaybeNull]T
; för argumentvärden motsvarar T?
[AllowNull]T
.
Likvärdigheten är viktig när du åsidosätter eller implementerar gränssnitt från en sammansättning som kompilerats med 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>()
}
default
begränsning
För kompatibilitet med befintlig kod där åsidosättande och explicit implementerade generiska metoder inte kunde innehålla explicita villkorssatser, behandlas T?
i en åsidosatt eller explicit implementerad metod som Nullable<T>
där T
är en värdetyp.
För att tillåta anteckningar för typparametrar som är begränsade till referenstyper tillät C#8 explicita where T : class
och where T : struct
begränsningar för den åsidosatta eller uttryckligen implementerade metoden.
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 { }
}
Om du vill tillåta anteckningar för typparametrar som inte är begränsade till referenstyper eller värdetyper tillåter C#9 en ny where T : default
begränsning.
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 { }
}
Det är ett fel att använda en default
-begränsning utanför en metodöverskrivning eller en explicit implementering.
Det är ett fel att använda en default
-begränsning när motsvarande typparameter i den åsidosatta eller gränssnittets metoden är begränsad till en referenstyp eller värdetyp.
Designa möten
C# feature specifications