Я пытаюсь прочитать ряд значений из двоичного файла, но я не узнаю, какие типы значений существуют до времени выполнения.
Упрощенный пример
У меня есть двоичный файл длиной 10 байт. Байты представляют по порядку int
, float
и short
. Я не знаю этого во время компиляции, но я знаю это во время выполнения с таким массивом:
Type[] types = new Type[3];
types[0] = typeof(int);
types[1] = typeof(float);
types[2] = typeof(short);
Вопрос
Итак, теперь, когда у меня есть этот список, могу ли я использовать эту информацию для быстрого чтения значений из файла? Единственный способ, который я могу придумать, это использовать большой блок if
, но он выглядит очень уродливо:
for (int i = 0; i < types.Length; i++)
{
if (types[i] == typeof(int))
{
int val = binaryfile.ReadInt32();
//... etc ...
}
else if (types[i] == typeof(float))
{
float val = binaryfile.ReadSingle();
//... etc ...
}
else if //... etc...
}
Но это некрасиво и громоздко. Мне интересно, могу ли я использовать информацию Type
в массиве types
, чтобы как-то «автоматизировать» это.
Что я пробовал
Одна идея, о которой я подумал, заключалась в том, чтобы прочитать необработанные байты в массив, а затем выполнить преобразование в массиве байтов. Итак, скажем, мой массив выглядит так:
byte[] buf = new byte[10] {
0x40, 0xE2, 0x01, 0x00,
0x79, 0xE9, 0xF6, 0x42,
0x39, 0x30 };
Он содержит значения int
, float
и short
123456, 123,456 и 12345 соответственно. Теперь я могу сделать следующее:
fixed (byte* bp = &buf[0])
{
int* ip = (int*)bp;
Console.WriteLine("int ptr: {0}", *ip);
}
Кажется, это работает хорошо, но есть две проблемы:
- Я не знаю, как маршалировать
*ip
обратно в управляемый домен. Я все еще не могу использовать свой список типов, как показано ниже:
fixed (byte* bp = &buf[0]) { (types[0])* ip = ((types[0])*)bp; // both errors here Console.WriteLine("int ptr: {0}", *ip); }
Это приводит к двум ошибкам времени компиляции в указанной строке:
Error 1 Invalid expression term ')'
Error 2 ) expected
Это пока все, что я придумал попробовать.
Я надеюсь, что кто-то может помочь. Я чувствую, что упускаю что-то простое, что сделало бы мою жизнь намного проще.
Обновлять
Я попробовал предложение Питера Дунихо, и, похоже, оно работает достаточно хорошо, хотя по сравнению с большим блоком if
наблюдается небольшое снижение производительности.
Вот некоторые результаты из файла ~ 100 МБ (все время указано в мс):
Метод Питера:
2025
2003
1954
1979
1958
if
блок:
1531
1488
1486
1489
Ничего особенного, хотя, поскольку я планирую работать с гораздо большими файлами (в диапазоне ГБ), эти несколько сотен миллисекунд складываются, поэтому я буду придерживаться уродливого блока if
, пока не найду что-то столь же быстрое.