Почему коллекция <enum> не может быть использована для <int?>?
Почему коллекция enum
недоступна для int?
enum Test { A = 1, B = 2 };
int? x = (int?)Test.A; // Valid
var collection1 = new[] { Test.A }.Cast<int>().ToList();
// InvalidCastException has thrown (Specified cast is not valid.)
var collection2 = new[] { Test.A }.Cast<int?>().ToList();
Ответы
Ответ 1
Метод Cast
может выполнять только преобразования бокса/распаковки, преобразования ссылок и преобразования между типом перечисления и его базовым типом интеграла. Unboxing должен быть в правильном типе, но - он не может распаковываться с типом NULL (в отличие от преобразования С#).
var collection1 = new[] { Test.A }.Cast<int>()
.Select(x => (int?) x)
.ToList();
Для каждого значения Cast
будет освобождено от установленного значения enum
до значения int
, а затем Select
преобразует значение int
в значение int?
.
В этом случае вы также можете уйти от этого:
var collection1 = new[] { Test.A }.Select(x => (int?) x)
.ToList();
то есть. no Cast
. Однако это не работает, если вместо этого у вас есть массив object
:
// Fails
var collection1 = new object[] { Test.A }.Select(x => (int?) x)
.ToList();
Вы не можете распаковать коробчатое значение перечисления в значение с нулевым значением int. Однако версия Cast
все еще работает в этом случае, поскольку она разделяет два шага (сначала распаковывает на int
, а затем переходит от int
в int?
.)
Ответ 2
Это потому, что внутри Cast()
делает что-то вроде:
object o = Test.A;
int i = (int)o; // This is valid.
int? ni = (int?)o; // This is not valid!
Вам нужно будет сначала Cast()
в int:
var collection3 = new[] { Test.A }.Cast<int>().ToList().Cast<int?>().ToList();
или вообще не использовать Cast()
:
var collection4 = new object[] { Test.A, null }.Select(i => i == null ? null : (int?)(int)i).ToList();
Ответ 3
Это не сработает, потому что нам нужно понять, что такое enum и что такое int? (nullable int)
int? на самом деле не int, это общий экземпляр Nullable, - синтаксис T? является сокращением для System.Nullable, где T - тип значения. Эти две формы взаимозаменяемы. Ссылка
Enum Основной тип элементов перечисления по умолчанию - int. Ссылка
Следовательно, существует неявное преобразование между int и enum. Но неявное преобразование между enum (int) и Nullable (который является совершенно другим ссылочным типом) не существует. Вот почему вы видите исключение InvalidCastException.
Где, как в первом выражении int? x = (int?)Test.A;
, вы принудительно устанавливаете явное преобразование в любое поле типа значения и получаете целое число или получаете нуль, что работает, потому что бокс перечисления в object
, а затем распаковывает его как int?
возвращает int.
Ответ 4
Я не знаю, почему Cast<>()
не работает, но вы можете использовать Select()
для выполнения того, что вы хотите.
var collection = new[] { Test.A }.Select(item => (int?)item).ToList();