Универсальный метод, который получает типизированное ненулевое значение и может возвращать нулевое значение

ниже приведен код, который представляет то, что я пытаюсь сделать:

private T? SomeMethod<T>(T prm)
{
    if (someCondition)
        return prm;

    return null;
}

Итак, идея такая: метод получает параметр, имеющий значение (не null), но возвращаемое значение метода может быть как значением, так и null.

Приведенный выше код не компилируется с сообщением «Невозможно преобразовать значение null в параметр типа 'T». Если я добавлю ограничение (где T: class или где T: struct), то он скомпилируется, но я не могу этого сделать, поскольку T может быть одновременно структурой и классом.

Итак, возможно ли это с C#?

default работает?

Progman 27.05.2024 22:18

Забавно, но для меня ошибка компилятора: «Невозможно преобразовать значение null в параметр типа «T», поскольку это может быть тип значения, не допускающий значения NULL. Вместо этого рассмотрите возможность использования «default (T)».

flackoverstow 27.05.2024 22:27

«но я не могу этого сделать, поскольку T может быть и структурой, и классом» — как вы предлагаете создать нулевую структуру? Или вы надеетесь, что компилятор будет по-разному расширять ваш универсальный код, чтобы возвращать тип значения, допускающий значение Null, или ссылочный тип null?

flackoverstow 27.05.2024 22:28
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете использовать default:

public T? SomeMethod<T>(T prm)
{
    // ...

    return default;
}

Но есть еще одна ошибка, о которой вам следует знать: для неограниченных универсальных параметров, если T является типом значения, тогда T и T? будут совпадать, т. е. SomeMethod<int> вернет int, а не int?, а для SomeMethod<int?> он вернет int? (см. этот ответ Больше подробностей). Существует немного грязный/хакерский способ решения этой проблемы — создайте 2 разных метода с параметрами по умолчанию и ограничьте их struct/class:

public T? SomeMethod<T>(T prm, T? _ = null) where T : struct
{
    // ...

    return default;
}

public T? SomeMethod<T>(T prm, T? _ = null) where T : class
{
    // ...

    return default;
}

Который будет правильно работать как для значений, так и для ссылочных типов и предотвратит/предупреждит передачу аналогов с нулевым значением (т. е. SomeMethod<int> вернет int?, а SomeMethod<int?> не скомпилирует).

Спасибо, теперь я лучше понимаю, как это работает.

Goran 28.05.2024 00:09

Другие вопросы по теме