C # ushort [] для преобразования строк; Это возможно? - PullRequest
2 голосов
/ 08 ноября 2008

У меня очень болезненная библиотека, которая на данный момент принимает строку C # как способ получения массивов данных; по-видимому, это облегчает сортировку для pinvokes.

Так как мне сделать массив ushort в строку байтами? Я пробовал:

int i;
String theOutData = "";
ushort[] theImageData = inImageData.DataArray;
 //this is as slow like molasses in January
 for (i = 0; i < theImageData.Length; i++) {
     byte[] theBytes = System.BitConverter.GetBytes(theImageData[i]);
     theOutData += String.Format("{0:d}{1:d}", theBytes[0], theBytes[1]);
 }

Я могу сделать это таким образом, но это не заканчивается ни в каком отдаленном приближении к разумному количеству времени.

Что мне здесь делать? Идти небезопасно? Пройдите какое-нибудь промежуточное IntPtr?

Если бы это был символ * в C ++, это было бы значительно проще ...

редактировать: вызов функции

DataElement.SetByteValue(string inArray, VL Length);

где VL - это «длина значения», тип DICOM, а сама функция генерируется SWIG в качестве оболочки для библиотеки C ++. Кажется, что выбранное представление является строковым, потому что оно может относительно легко пересекать управляемые / неуправляемые границы, но во всем коде C ++ в проекте (это GDCM) char * просто используется в качестве байтового буфера. Поэтому, когда вы хотите установить указатель на буфер изображения, в C ++ это довольно просто, но в C # я застрял с этой странной проблемой.

Это хакерация, и я знаю, что, вероятно, лучше всего заставить библиотеку SWIG работать правильно. Я действительно не знаю, как это сделать, и предпочел бы быстрый обходной путь на стороне C #, если таковой существует.

Ответы [ 5 ]

6 голосов
/ 08 ноября 2008

P / Invoke может фактически обрабатывать то, что вам нужно, используя StringBuilder для создания доступных для записи буферов, например, см. pinvoke.net в GetWindowText и связанные с ним функции .

Однако, за исключением того, что с данными как ushort, я предполагаю, что они закодированы в UTF-16LE. В этом случае вы можете использовать Encoding.Unicode.GetString (), но это будет ожидать байтового массива, а не массива ushort. Чтобы превратить ваши ushorts в байты, вы можете выделить отдельный байтовый массив и использовать Buffer.BlockCopy, что-то вроде этого:

ushort[] data = new ushort[10];
for (int i = 0; i < data.Length; ++i)
    data[i] = (char) ('A' + i);

string asString;
byte[] asBytes = new byte[data.Length * sizeof(ushort)];
Buffer.BlockCopy(data, 0, asBytes, 0, asBytes.Length);
asString = Encoding.Unicode.GetString(asBytes);

Однако, если небезопасный код в порядке, у вас есть другой вариант. Получите начало массива как ushort *, и приведите его к типу char *, а затем передайте его строковому конструктору, например:

string asString;
unsafe
{
    fixed (ushort *dataPtr = &data[0])
        asString = new string((char *) dataPtr, 0, data.Length);
}
1 голос
/ 18 декабря 2008

Только к вашему сведению, это было исправлено в более поздней версии (gdcm 2.0.10). Смотрите здесь:

http://gdcm.sourceforge.net/

-> http://apps.sourceforge.net/mediawiki/gdcm/index.php?title=GDCM_Release_2.0

1 голос
/ 08 ноября 2008

Одна вещь, которую вы можете сделать, это переключиться с использования строки на stringBuilder, это значительно повысит производительность.

Если вы хотите использовать небезопасный код, вы можете использовать указатели и реализовывать ваш код на c # так же, как ваш c ++. Или вы можете написать небольшой c ++ \ cli dll, который реализует эту функциональность.

0 голосов
/ 08 ноября 2008

Посмотрите на Буфер класс:

ushort[] theImageData = inImageData.DataArray;

byte[] buf = new byte[Buffer.ByteLength(theImageData)]; // 2 bytes per short
Buffer.BlockCopy(theImageData, 0, buf, 0, Buffer.ByteLength(theImageData));

string theOutData = System.Text.Encoding.ASCII.GetString(buf);
0 голосов
/ 08 ноября 2008

Мне это не очень нравится, но, похоже, это работает, учитывая следующие предположения:

1. Каждый ushort представляет собой ASCII-символ от 0 до 127

2. (Хорошо, я думаю, что есть только одно предположение)

        ushort[] data = inData; // The ushort array source

        Byte[] bytes = new Byte[data.Length];  // Assumption - only need one byte per ushort

        int i = 0;
        foreach(ushort x in data) {
            byte[] tmp = System.BitConverter.GetBytes(x);
            bytes[i++] = tmp[0];
            // Note: not using tmp[1] as all characters in 0 < x < 127 use one byte.
        }

        String str = Encoding.ASCII.GetString(bytes);

Я уверен, что есть лучшие способы сделать это, но это все, что я мог придумать быстро.

...