Udostępnij za pośrednictwem


Adnotacje parametrów typu nieograniczonego

Notatka

Ten artykuł jest specyfikacją funkcji. Specyfikacja służy jako dokument projektowy dla funkcji. Zawiera proponowane zmiany specyfikacji wraz z informacjami wymaganymi podczas projektowania i opracowywania funkcji. Te artykuły są publikowane do momentu sfinalizowania proponowanych zmian specyfikacji i włączenia ich do obecnej specyfikacji ECMA.

Mogą wystąpić pewne rozbieżności między specyfikacją funkcji a ukończoną implementacją. Te różnice są uchwycone w notatkach ze spotkań dotyczących projektu języka (LDM).

Więcej informacji na temat procesu wdrażania specyfikacji funkcji można znaleźć w standardzie języka C# w artykule dotyczącym specyfikacji .

Problem z mistrzem: https://github.com/dotnet/csharplang/issues/3297

Streszczenie

Zezwalaj na adnotacje nullable dla parametrów typu, które nie ograniczają się do typów wartości lub typów odwołań: T?.

static T? FirstOrDefault<T>(this IEnumerable<T> collection) { ... }

adnotacja ?

W języku C#8 adnotacje ? można zastosować tylko do parametrów typu, które były jawnie ograniczone do typów wartości lub typów odwołań. W języku C#9 adnotacje ? można zastosować do dowolnego parametru typu, niezależnie od ograniczeń.

Jeśli parametr typu nie jest jawnie ograniczony do typów wartości, adnotacje można stosować tylko w kontekście #nullable enable.

Jeśli parametr typu T zostanie zastąpiony typem referencyjnym, to T? reprezentuje pustą instancję tego typu referencyjnego, która akceptuje wartość null.

var s1 = new string[0].FirstOrDefault();  // string? s1
var s2 = new string?[0].FirstOrDefault(); // string? s2

Jeśli T jest zastępowany typem wartości, T? reprezentuje wystąpienie T.

var i1 = new int[0].FirstOrDefault();  // int i1
var i2 = new int?[0].FirstOrDefault(); // int? i2

Jeśli T jest zastępowany typem adnotacji U?, T? reprezentuje typ adnotacji U?, a nie U??.

var u1 = new U[0].FirstOrDefault();  // U? u1
var u2 = new U?[0].FirstOrDefault(); // U? u2

Jeśli T jest zastępowany typem U, T? reprezentuje U?, nawet w kontekście #nullable disable.

#nullable disable
var u3 = new U[0].FirstOrDefault();  // U? u3

W przypadku wartości zwracanych T? jest równoważne [MaybeNull]T; dla wartości argumentów T? jest równoważna [AllowNull]T. Równoważność jest ważna podczas zastępowania lub implementowania interfejsów z zestawu skompilowanego przy użyciu języka 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>()
}

ograniczenie default

Aby uzyskać zgodność z istniejącym kodem, w którym zastępowane i jawnie implementowane metody ogólne nie mogą zawierać jawnych klauzul ograniczeń, T? w przesłoniętej lub jawnie zaimplementowanej metodzie jest traktowana jako Nullable<T>, gdzie T jest typem wartości.

Aby zezwolić na adnotacje dotyczące parametrów typu ograniczonych do typów odwołań, C#8 pozwolił na jawne where T : class i where T : struct ograniczenia w odniesieniu do metod zastępowanych lub jawnie zaimplementowanych.

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 { }
}

Aby zezwolić na adnotacje dla parametrów typu, które nie są ograniczone do typów odwołań lub typów wartości, język C#9 zezwala na nowe ograniczenie 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 { }
}

Jest błędem używanie ograniczenia default w innych przypadkach niż zastąpienie metody lub jawna implementacja. Używanie ograniczenia default jest błędem, kiedy parametr typu w metodzie przeciążonej lub interfejsowej jest ograniczony do typu referencyjnego lub typu wartościowego.

Spotkania projektowe