Я работаю с некоторыми данными, которые считываются из двоичного файла и могут быть одного из нескольких примитивных типов, например, int16, int32, single, double и т. Д.
Например, скажем, у меня есть 3файлы:
- Файл A: содержит все int16
- Файл B: содержит все int32
- Файл C: содержит все отдельные
Заголовок каждого файла имеет код для типа данных, например, Файл A будет иметь поле заголовка dtype: 0
, Файл B будет иметь поле заголовка dtype: 1
, а Файл C будет иметь поле заголовка dtype: 2
.
Файлы представляют собой собственный формат изображения - представьте себе растровое изображение, но где тело растрового изображения может быть int16, int32 или одиночным.
Учитывая, что я прочитал данные из двоичного файлафайл, я использую сопоставление с шаблоном для преобразования двоичных данных в тип, указанный в заголовке файла.
Скажем, у меня есть массив / буфер, содержащий n байтов, считанных из файлового потока:
let buffer: byte[] = … <-- read bytes into here
let container = new ResizeArray<obj>() //maintain same type in pattern match
let matchDatatype (dtype: int) = // Let's read File B
match dtype with
| 0 ->
let typeBuffer: int16[] = numBytesInFile/2 |> Array.zeroCreate
while stream.Position < stream.Length do
stream.Read(buffer, 0, numBytesInFile) |> ignore
Buffer.BlockCopy(buffer, 0, typeBuffer, 0, numBytesInFile)
typeBuffer |> Array.chunkBySize 8 |> container.Add
| 1 -> // Reading int32 from File B
let typeBuffer: int32[] = numBytesInFile/4 |> Array.zeroCreate
while stream.Position < stream.Length do
stream.Read(buffer, 0, numBytesInFile) |> ignore
Buffer.BlockCopy(buffer, 0, typeBuffer, 0, numBytesInFile)
typeBuffer |> Array.chunkBySize 8 |> container.Add
| 2 -> ...
….
Так что, если я читаю из файла B, код данных заголовка говорит: «читать этиНапример, int32 ", происходят другие вещи, и у меня есть ResizeArray<obj>
, который содержит массив массивов (например, int[][]
)
Чтобы получить нужный мне массив, я просто нарезал ResizeArray (container.[0]
) и я получаю obj
.
Мне нужно вернуть obj
обратно в тип массива.Проблема в том, что, поскольку я читаю файлы нескольких возможных типов, у меня возникают проблемы с обобщением кода для работы со всеми различными файлами.Я знаю, что могу сделать container.[0] :?> int[][]
, если знаю, что файл будет иметь все целые числа, но я не знаю, во время разработки.
Я знаю, что не могу сохранить тип массива какпозвольте связывание из GetType (), что еще больше сбивает с толку, как я должен подходить к этому (например, container.[0] :?> container.[0].GetType()
не работает).
Используя fsi, вот пример того, что я пытаюсь сделать, если я прочитализ файла B (int):
> let someArray = [|[|0;1;2|];|[3;4;5|]|];; <-- say I read this from File B
val it : int [] [] = [|[|0; 1; 2|];[|3; 4; 5|]|]
> container.Add(someArray)
val it: unit = ()
> let arrObj = container.[0]
val it : obj = [|[|0; 1; 2|];[|3; 4; 5|]|]
> arrObj.GetType().FullName;;
val it : string = "System.Int32[][]"
> arrObj :?> int[][] <-- I can't know this at design time
val it : int [] [] = [|[|0; 1; 2|];[|3; 4; 5|]|]
Последний шаг - место возникновения проблемы.Возвращенный объект типа ясно показывает, что он знает, что массив не является объектом - что это на самом деле int[][]
.Как я могу программно / динамически выполнить это понижение, не говоря явно «понижение до int[][]
?»Мне нужно, чтобы это работало и для одиночных [] [] и для int16 [] [] случаев.
Или мой подход неверен, когда речь идет о коде, который может гибко считывать данные разных типов?Моя единственная другая мысль - сделать чудовищную попытку поймать, но я чувствую, что это не очень идиоматично.
Моя предыдущая работа была сделана в MATLAB, так что это новая проблема для меня, так как я мог простовыведите строки и сгенерируйте нужный мне код.
edit : использование Buffer.BlockCopy вместо BitConverter
edit 2 : я вижу, F # может определитьвведите псевдонимы, используя type
, где
[accessibility-modifier] type-abbreviation = type-name
Однако это не позволяет мне делать что-то вроде type ArrType = arrObj.GetType()
.Самое близкое, что я думаю о том, что мне нужно, это C-подобный typedef.
edit 3 : Я смотрел на то, что называется динамическим созданием экземпляров, используя Activator.CreateInstance()
- это тот случай, когда можно использовать это?