#c# #icomparable #unboxing
Вопрос:
Во-первых, два примера:
// This works
int foo = 43;
long lFoo = foo;
// This doesn't
object foo = (int)43;
long? nullFoo = foo as long?; // returns null
long lFoo = (long)foo; // throws InvalidCastException
if (foo.GetType() == typeof(int))
Console.WriteLine("But foo is an int..."); // This gets written out
Теперь я предполагаю, почему второе не работает из-за бокса. Цель этого кода состоит в том, чтобы реализовать IComparable
. Мне нужен какой-то способ принудить объект либо к длинному, либо к длинному, в зависимости от обстоятельств, или, если это ни то, ни другое, чем выдавать ошибку. Я не хочу реализовывать проверки для каждого базового числового типа (byte, int, long, ubyte,…). Я бы предпочел просто отловить их в самом большом числовом типе и разобраться с этим таким образом. Мысли всех присутствующих здесь умных людей? Как я могу распаковать объект, предпочтительно избегая отражения, но я полагаю, что это единственный способ… Или я должен просто не реализовывать непатентованную версию IComparable
?
Редактировать:
Кажется, это работает, но похоже на ужасный взлом проблемы. Это только из-за меня?
long lFoo = long.Parse(foo.ToString());
Комментарии:
1. Мне было бы интересно узнать, почему именно вам нужно это сделать. Как это связано с IComparable?
Ответ №1:
object foo = (int) 43;
long lFoo = ((IConvertible) foo).ToInt64(null);
Комментарии:
1. Это действительно работает… Ура базовым типам, которые наследуют интерфейсы. Никогда до конца не понимал этой части, но тем не менее полезен.
Ответ №2:
Когда вы приводите к типу значения, вы действительно заставляете операцию распаковки IL, которая требует, чтобы тип, к которому вы приводите, точно соответствовал упакованному значению; нет никаких преобразований, неявных или явных, которые могут произойти одновременно.
Обычно это означает, что вам нужно либо выполнить переключение с использованием кода типа (или если/иначе, если используются типы), либо, в вашем случае, выполнить проверку на наличие null с последующим преобразованием.ToInt64(), который должен правильно с этим справиться.
Комментарии:
1. На самом деле это не требует точного соответствия. Вы можете распаковать упакованное перечисление в качестве базового типа или наоборот (несмотря на то, что информация о типе действительно существует). Вы также можете распаковать файл в соответствующий тип, допускающий значение null. Существуют некоторые подобные нечетные преобразования, которые позволяет среда CLR, например, int[] в uint[].
Ответ №3:
Это не только вы, однако tryparse не вызывает исключения.
object foo = (int)43;
long outVal;
if(long.TryParse(foo.ToString(),out outVal))
{
//take action with correct value of long
}
else
{
//maybe passed you another type of object
}
Комментарии:
1. Это не тот путь, по которому нужно идти. Помимо того, что это намного более неэффективно, я считаю, что нет никакой гарантии, что формат строки, сгенерированный toString (), действительно может быть проанализирован сразу с помощью функции Parse/TryParse() (т. Е. Не во всех вариантах он будет работать туда и обратно).