Обнуляемые ссылочные типы: как указать «T»? тип без ограничения класса или структуры - PullRequest
9 голосов
/ 03 мая 2019

Я хочу создать универсальный класс, который имеет член типа T.T может быть классом, обнуляемым классом, структурой или обнуляемой структурой.Так что в принципе все что угодно.Это упрощенный пример, который показывает мою проблему:

#nullable enable

class Box<T> {
    public T Value { get; }

    public Box(T value) {
        Value = value;
    }

    public static Box<T> CreateDefault()
        => new Box<T>(default(T));
}

Из-за использования новой функции #nullable enable я получаю следующее предупреждение: Program.cs(11,23): warning CS8653: A default expression introduces a null value when 'T' is a non-nullable reference type.

Это предупреждение имеет смысл для меня.Затем я попытался исправить это, добавив ? к параметру свойства и конструктора:

#nullable enable

class Box<T> {
    public T? Value { get; }

    public Box(T? value) {
        Value = value;
    }

    public static Box<T> CreateDefault()
        => new Box<T>(default(T));
}

Но теперь вместо этого я получаю две ошибки:

Program.cs(4,12): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.
Program.cs(6,16): error CS8627: A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.

Однако,Я не хочу добавлять ограничение. Мне все равно, является ли T классом или структурой.

Очевидное решение - заключить нарушающие члены в директиву #nullable disable.,Однако, как и #pragma warning disable, я бы хотел избежать этого, если в этом нет необходимости.Есть ли другой способ заставить мой код компилироваться, не отключая проверки обнуляемости или предупреждение CS8653?

$ dotnet --info
.NET Core SDK (reflecting any global.json):
 Version:   3.0.100-preview4-011223
 Commit:    118dd862c8

Ответы [ 2 ]

0 голосов
/ 04 мая 2019

Джефф Меркадо поднял хороший комментарий в комментариях:

Я думаю, у вас есть несколько противоречивых целей. Вы хотите иметь представление о поле по умолчанию, но для справочных типов, что еще является подходящим значением по умолчанию? Значение по умолчанию равно нулю для ссылочных типов, что напрямую конфликтует с использованием нулевых ссылочных типов. Возможно, вам придется ограничить T типами, которые могут быть созданы по умолчанию (new ()).

Например, default(T) для T = string будет null, поскольку во время выполнения нет различия между string и string?. Это текущее ограничение языковой функции.

Я обошел эту проблему, создав отдельные CreateDefault методы для каждого случая:

#nullable enable

class Box<T> {
    public T Value { get; }

    public Box(T value) {
        Value = value;
    }
}

static class CreateDefaultBox
{
    public static Box<T> ValueTypeNotNull<T>() where T : struct
        => new Box<T>(default);

    public static Box<T?> ValueTypeNullable<T>() where T : struct
        => new Box<T?>(null);

    public static Box<T> ReferenceTypeNotNull<T>() where T : class, new()
        => new Box<T>(new T());

    public static Box<T?> ReferenceTypeNullable<T>() where T : class
        => new Box<T?>(null);
}

Этот кажется мне безопасным , за счет более уродливых сайтов вызовов (CreateDefaultBox.ReferenceTypeNullable<object>() вместо Box<object?>.CreateDefault()). В примере класса, который я разместил, я бы просто полностью удалил методы и напрямую использовал конструктор Box. Ну хорошо.

0 голосов
/ 03 мая 2019
class Box<T> {
    public T! Value { get; }

    public Box(T! value) {
        Value = value;
    }

    public static Box<T> CreateDefault()
        => new default!;
}

Что значит ноль!заявление значит?

...