Поделиться через


Аннотации неконстраинтных параметров типов

Заметка

Эта статья является спецификацией компонентов. Спецификация служит проектным документом для функции. Включает предлагаемые изменения спецификации, а также информацию, необходимую во время проектирования и разработки функции. Эти статьи публикуются до тех пор, пока предложенные изменения спецификации не будут завершены и включены в текущую спецификацию ECMA.

Может возникнуть некоторое несоответствие между спецификацией компонентов и завершенной реализацией. Эти различия были зафиксированы в соответствующих совещаниях по разработке языка (LDM).

Дополнительные сведения о процессе внедрения спецификаций функций в стандарт языка C# см. в статье о спецификациях .

Вопрос чемпиона: https://github.com/dotnet/csharplang/issues/3297

Сводка

Разрешить заметки, допускающие значение NULL, для параметров типа, которые не ограничены типами значений или ссылочными типами: T?.

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

заметка ?

В C#8 ? заметки можно применять только к параметрам типа, которые были явно ограничены типами значений или ссылочными типами. В C#9 ? заметки можно применять к любому параметру типа независимо от ограничений.

Если параметр типа явно не ограничен типами значений, заметки могут применяться только в контексте #nullable enable.

Если параметр типа T заменен ссылочным типом, T? представляет экземпляр ссылочного типа, допускающий значение NULL.

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

Если T заменен типом значения, T? представляет экземпляр T.

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

Если T заменен аннотированным типом U?, то T? представляет аннотированный тип U? вместо U??.

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

Если T заменен типом U, T? представляет U?даже в контексте #nullable disable.

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

Для возвращаемых значений T? эквивалентно [MaybeNull]T; для значений аргументов T? эквивалентен [AllowNull]T. Эквивалентность важна при переопределении или реализации интерфейсов из сборки, скомпилированной с помощью 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

Для совместимости с существующим кодом, где переопределённые или явно реализованные универсальные методы не могли включать явные предложения ограничений, T? в переопределённом или явно реализованном методе рассматривается как Nullable<T>, где T является типом значения.

Чтобы разрешить аннотации для параметров типа, ограниченных ссылочными типами, в C#8 были разрешены явные ограничения where T : class и where T : struct для переопределенного или явно реализованного метода.

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

Чтобы разрешить заметки для параметров типа, которые не ограничены ссылочными типами или типами значений, C#9 разрешает новое ограничение 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 { }
}

Это ошибка использовать ограничение default в любом контексте, кроме переопределения метода или явной реализации. Это ошибка использования ограничения default, если соответствующий параметр типа в переопределенном или интерфейсном методе ограничен ссылочным типом или типом значения.

Совещания по дизайну