Вопрос о боксе C#

#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() (т. Е. Не во всех вариантах он будет работать туда и обратно).