У меня есть общий метод с этим (фиктивным) кодом (да, я знаю, что у 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."
Могу ли я избежать этой ошибки?
Жаль, что T? в подписи не работает. @ Alexander-ReinstateMonica Я прочитал статью, но не нашел способа вернуть null независимо от типа ссылки или значения.
@mireazma Это слишком мало информации, чтобы я мог помочь. Вам следует открыть новый вопрос.





return default(T);
Эта ссылка: msdn.microsoft.com/en-us/library/xwth0h0d(VS.80).aspx должна объяснить, почему.
Черт возьми, я бы сэкономил много времени, если бы знал об этом ключевом слове - спасибо, Рикардо!
Я удивлен, что это не набрало больше голосов, поскольку ключевое слово default - более комплексное решение, позволяющее использовать не ссылочные типы в сочетании с числовыми типами и структурами. Хотя принятый ответ решает проблему (и действительно полезен), он лучше отвечает, как ограничить возвращаемый тип типами, допускающими значение NULL / ссылочными типами.
Возьмите рекомендацию по ошибке ... и либо пользователя default(T), либо new T.
Вам нужно будет добавить сравнение в свой код, чтобы убедиться, что оно было допустимым, если вы пойдете по этому маршруту.
В противном случае потенциально можно рассмотреть выходной параметр для «найдено совпадение».
Два варианта:
default(T), что означает, что вы вернете null, если T является ссылочным типом (или типом значения, допускающим значение NULL), 0 для int, '\0' для char и т. д. (Таблица значений по умолчанию (Справочник по C#))where T : class, а затем верните null как обычноЧто, если мой возвращаемый тип - это перечисление, а не класс? Я не могу указать T: enum :(
В .NET перечисление - это очень тонкая (и довольно протекающая) оболочка для целочисленного типа. По соглашению в качестве значения перечисления "по умолчанию" используется ноль.
Я думаю, проблема в том, что если вы используете этот общий метод, чтобы сказать, преобразовать объект базы данных из DbNull в Int, и он вернет значение по умолчанию (T), где T - это int, он вернет 0. Если это число равно на самом деле имеет смысл, тогда вы будете передавать неверные данные в тех случаях, когда это поле было пустым. Или лучшим примером может быть DateTime. Если поле было чем-то вроде «DateClosed» и было возвращено как null, потому что учетная запись все еще открыта, фактически по умолчанию (DateTime) было бы 1/1/0000, подразумевая, что учетная запись была закрыта до того, как были изобретены компьютеры.
@Sinaesthetic: Значит, вы бы вместо этого конвертировали в Nullable<int> или Nullable<DateTime>. Если вы используете тип, не допускающий значения NULL, и вам нужно представить значение NULL, вы просто напрашиваетесь на проблемы.
Я согласен, я просто хотел поднять этот вопрос. Я думаю, что то, что я делал, больше похоже на MyMethod <T> (); предположить, что это тип, не допускающий значения NULL, и MyMethod <T?> (); предположить, что это тип, допускающий значение NULL. Поэтому в моих сценариях я мог бы использовать временную переменную, чтобы поймать нуль и перейти оттуда.
Большое спасибо, дружище! :)
Начиная с C# 7.1 (август 2017 г.) вы можете немного упростить синтаксис варианта 1 в return default;, поскольку тип определяется автоматически.
Другой вариант - добавить это в конец объявления:
where T : class
where T: IList
Таким образом, вы сможете вернуть значение null.
Если оба ограничения относятся к одному и тому же типу, вы указываете тип один раз и используете запятую, например where T : class, IList. Если у вас есть ограничения для разных типов, вы повторяете токен where, как в where TFoo : class where TBar : IList.
Вы можете просто изменить свои ограничения:
where T : class
Тогда разрешен возврат null.
Спасибо. Я не могу выбрать 2 ответа в качестве принятого решения, поэтому я выбираю Джона Скита, потому что его ответ имеет два решения.
@Migol это зависит от ваших требований. Возможно, их проект действительно требует, чтобы это был IDisposable. Да, в большинстве случаев это не обязательно. System.String, например, не реализует IDisposable. Ответчик должен был это пояснить, но это не означает, что ответ неверный. :)
@Migol Я понятия не имею, почему у меня там IDisposable. Удаленный.
Добавьте ограничение класса в качестве первого ограничения к вашему универсальному типу.
static T FindThing<T>(IList collection, int id) where T : class, IThing, new()
Спасибо. Я не могу выбрать 2 ответа в качестве принятого решения, поэтому я выбираю Джона Скита, потому что его ответ имеет два решения.
решение 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;
}
Если у вас есть объект, вам нужно привести тип
return (T)(object)(employee);
если вам нужно вернуть null.
return default(T);
Привет, user725388, проверьте первый вариант
Вот рабочий пример возвращаемых значений 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).
Ниже приведены два варианта, которые вы можете использовать.
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 хороший улов
Для полноты картины полезно знать, что вы также можете сделать это:
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); подойдет.
Могут ли ссылочные типы, допускающие значение NULL (в C# 8), быть лучшим решением этой проблемы сейчас? docs.microsoft.com/en-us/dotnet/csharp/nullable-references Возвращение
nullнезависимо от того, является лиTObject,intилиchar.