Как я могу вернуть NULL из универсального метода в C#?

У меня есть общий метод с этим (фиктивным) кодом (да, я знаю, что у IList есть предикаты, но мой код не использует IList, а какую-то другую коллекцию, в любом случае это не имеет отношения к вопросу ...)

static T FindThing<T>(IList collection, int id) where T : IThing, new()
{
    foreach T thing in collecion
    {
        if (thing.Id == id)
            return thing;
    }
    return null;  // ERROR: Cannot convert null to type parameter 'T' because it could be a value type. Consider using 'default(T)' instead.
}

Это дает мне ошибку сборки

"Cannot convert null to type parameter 'T' because it could be a value type. Consider using 'default(T)' instead."

Могу ли я избежать этой ошибки?

Могут ли ссылочные типы, допускающие значение NULL (в C# 8), быть лучшим решением этой проблемы сейчас? docs.microsoft.com/en-us/dotnet/csharp/nullable-references Возвращение null независимо от того, является ли TObject, int или char.

Alexander 23.05.2020 19:35

Жаль, что T? в подписи не работает. @ Alexander-ReinstateMonica Я прочитал статью, но не нашел способа вернуть null независимо от типа ссылки или значения.

mireazma 09.10.2020 11:03

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

Alexander 09.10.2020 17:03
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
581
3
189 914
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

return default(T);

Эта ссылка: msdn.microsoft.com/en-us/library/xwth0h0d(VS.80).aspx должна объяснить, почему.

Harper Shelby 19.11.2008 17:59

Черт возьми, я бы сэкономил много времени, если бы знал об этом ключевом слове - спасибо, Рикардо!

Ana Betts 19.11.2008 18:06

Я удивлен, что это не набрало больше голосов, поскольку ключевое слово default - более комплексное решение, позволяющее использовать не ссылочные типы в сочетании с числовыми типами и структурами. Хотя принятый ответ решает проблему (и действительно полезен), он лучше отвечает, как ограничить возвращаемый тип типами, допускающими значение NULL / ссылочными типами.

Steve Jackson 15.09.2014 22:30

Возьмите рекомендацию по ошибке ... и либо пользователя default(T), либо new T.

Вам нужно будет добавить сравнение в свой код, чтобы убедиться, что оно было допустимым, если вы пойдете по этому маршруту.

В противном случае потенциально можно рассмотреть выходной параметр для «найдено совпадение».

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

Два варианта:

  • Вернуть default(T), что означает, что вы вернете null, если T является ссылочным типом (или типом значения, допускающим значение NULL), 0 для int, '\0' для char и т. д. (Таблица значений по умолчанию (Справочник по C#))
  • Ограничьте T как ссылочный тип с ограничением where T : class, а затем верните null как обычно

Что, если мой возвращаемый тип - это перечисление, а не класс? Я не могу указать T: enum :(

Justin 30.08.2011 06:01

В .NET перечисление - это очень тонкая (и довольно протекающая) оболочка для целочисленного типа. По соглашению в качестве значения перечисления "по умолчанию" используется ноль.

Mike Chamberlain 05.03.2012 07:53

Я думаю, проблема в том, что если вы используете этот общий метод, чтобы сказать, преобразовать объект базы данных из DbNull в Int, и он вернет значение по умолчанию (T), где T - это int, он вернет 0. Если это число равно на самом деле имеет смысл, тогда вы будете передавать неверные данные в тех случаях, когда это поле было пустым. Или лучшим примером может быть DateTime. Если поле было чем-то вроде «DateClosed» и было возвращено как null, потому что учетная запись все еще открыта, фактически по умолчанию (DateTime) было бы 1/1/0000, подразумевая, что учетная запись была закрыта до того, как были изобретены компьютеры.

Sinaesthetic 21.11.2012 02:26

@Sinaesthetic: Значит, вы бы вместо этого конвертировали в Nullable<int> или Nullable<DateTime>. Если вы используете тип, не допускающий значения NULL, и вам нужно представить значение NULL, вы просто напрашиваетесь на проблемы.

Jon Skeet 21.11.2012 02:28

Я согласен, я просто хотел поднять этот вопрос. Я думаю, что то, что я делал, больше похоже на MyMethod <T> (); предположить, что это тип, не допускающий значения NULL, и MyMethod <T?> (); предположить, что это тип, допускающий значение NULL. Поэтому в моих сценариях я мог бы использовать временную переменную, чтобы поймать нуль и перейти оттуда.

Sinaesthetic 21.11.2012 03:12

Большое спасибо, дружище! :)

Jakub Kučera 19.07.2017 23:31

Начиная с C# 7.1 (август 2017 г.) вы можете немного упростить синтаксис варианта 1 в return default;, поскольку тип определяется автоматически.

Jeppe Stig Nielsen 22.09.2019 11:11

Другой вариант - добавить это в конец объявления:

    where T : class
    where T: IList

Таким образом, вы сможете вернуть значение null.

Если оба ограничения относятся к одному и тому же типу, вы указываете тип один раз и используете запятую, например where T : class, IList. Если у вас есть ограничения для разных типов, вы повторяете токен where, как в where TFoo : class where TBar : IList.

Jeppe Stig Nielsen 22.09.2019 11:17

Вы можете просто изменить свои ограничения:

where T : class

Тогда разрешен возврат null.

Спасибо. Я не могу выбрать 2 ответа в качестве принятого решения, поэтому я выбираю Джона Скита, потому что его ответ имеет два решения.

edosoft 19.11.2008 18:16

@Migol это зависит от ваших требований. Возможно, их проект действительно требует, чтобы это был IDisposable. Да, в большинстве случаев это не обязательно. System.String, например, не реализует IDisposable. Ответчик должен был это пояснить, но это не означает, что ответ неверный. :)

ahwm 31.08.2018 01:34

@Migol Я понятия не имею, почему у меня там IDisposable. Удаленный.

TheSoftwareJedi 31.08.2018 22:36

Добавьте ограничение класса в качестве первого ограничения к вашему универсальному типу.

static T FindThing<T>(IList collection, int id) where T : class, IThing, new()

Спасибо. Я не могу выбрать 2 ответа в качестве принятого решения, поэтому я выбираю Джона Скита, потому что его ответ имеет два решения.

edosoft 19.11.2008 18:18

решение TheSoftwareJedi работает,

также вы можете заархивировать его, используя пару значений и типов, допускающих значение NULL:

static T? FindThing<T>(IList collection, int id) where T : struct, IThing
{
    foreach T thing in collecion
    {
        if (thing.Id == id)
            return thing;
    }
    return null;
}
  1. Если у вас есть объект, вам нужно привести тип

    return (T)(object)(employee);
    
  2. если вам нужно вернуть null.

    return default(T);
    

Привет, user725388, проверьте первый вариант

Jogi Joseph George 08.08.2017 15:57

Вот рабочий пример возвращаемых значений Nullable Enum:

public static TEnum? ParseOptional<TEnum>(this string value) where TEnum : struct
{
    return value == null ? (TEnum?)null : (TEnum) Enum.Parse(typeof(TEnum), value);
}

Начиная с C# 7.3 (май 2018 г.), вы можете улучшить ограничение для where TEnum : struct, Enum. Это гарантирует, что вызывающий объект случайно не предоставит тип значения, не являющийся перечислением (например, int или DateTime).

Jeppe Stig Nielsen 22.09.2019 11:26

Ниже приведены два варианта, которые вы можете использовать.

return default(T);

или же

where T : class, IThing
 return null;

Еще одна альтернатива 2 ответам, представленным выше. Если вы измените тип возврата на object, вы можете вернуть null, в то же время приведя ненулевой возврат.

static object FindThing<T>(IList collection, int id)
{
    foreach T thing in collecion
    {
        if (thing.Id == id)
            return (T) thing;
    }
    return null;  // allowed now
}

Обратная сторона: это потребовало бы, чтобы вызывающая сторона метода приводила возвращаемый объект (в ненулевом случае), что подразумевает упаковку -> меньшую производительность. Я прав?

Csharpest 19.02.2020 13:44

@Csharpest хороший улов

Impostor 15.03.2021 15:07

Для полноты картины полезно знать, что вы также можете сделать это:

return default;

Возвращает то же, что и return default(T);

Для меня это работает как есть. Где именно проблема?

public static T FindThing<T>(this IList collection, int id) where T : IThing, new()
{
    foreach (T thing in collection)
    {
        if (thing.Id == id)
            return thing;
        }
    }

    return null; //work
    return (T)null; //work
    return null as T; //work
    return default(T); //work


}

Вы пробовали этот код? Только return default(T); подойдет.

E. Shcherbo 19.03.2021 19:39

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