С#:в общем преобразовать неуправляемый массив в управляемый список

StackOverflow https://stackoverflow.com/questions/977149

  •  13-09-2019
  •  | 
  •  

Вопрос

Я имею дело с набором собственных функций, которые возвращают данные через динамически выделяемые массивы.Функции принимают на вход указатель ссылки, а затем указывают его на результирующий массив.

Например:

typedef struct result
{
   //..Some Members..//
}

int extern WINAPI getInfo(result**);

После вызова 'result' указывает на массив результатов*, завершающийся нулем.

Я хочу создать управляемый список из этого неуправляемого массива.Я могу сделать следующее:

struct Result
{
   //..The Same Members..//
}

public static unsafe List<Result> getManagedResultList(Result** unmanagedArray)
{
    List<Result> resultList = new List<Result>();

    while (*unmanagedArray != null)
    {
       resultList.Add(**unmanagedArray);
       ++unmanaged;
    }
    return result;
}

Это работает, будет утомительно и некрасиво переопределять структуру для каждого типа, с которой мне придется иметь дело (~ 35).Мне нужно решение, которое является общим для типа структуры в массиве.С этой целью я попробовал:

public static unsafe List<T> unmanagedArrToList<T>(T** unmanagedArray)
{ 
    List<T> result = new List<T>();
    while (*unmanagedArray != null)
    {
        result.Add((**unmanagedArray));
        ++unmanagedArray;
    }
    return result;
}

Но это не скомпилируется, потому что вы не можете «взять адрес, получить размер или объявить указатель на управляемый тип ('T')».

Я также пытался сделать это без использования небезопасного кода, но столкнулся с проблемой, заключающейся в том, что Marshal.Copy() необходимо знать размер неуправляемого массива.Я мог определить это только с помощью небезопасного кода, поэтому использование Marshal.Copy() в данном случае не принесло никакой пользы.

Что мне не хватает?Может ли кто-нибудь предложить общий подход к этой проблеме?

Это было полезно?

Решение

Вы можете сделать разумное предположение, что размер и представление всех указателей одинаковы (не уверен, гарантирует ли это спецификация C#, но на практике вы обнаружите, что это так).Таким образом, вы можете лечить свой T** как IntPtr*.Кроме того, я не понимаю, как Marshal.Copy поможет вам здесь, поскольку он имеет перегрузки только для встроенных типов.Так:

public static unsafe List<T> unmanagedArrToList<T>(IntPtr* p)
{ 
    List<T> result = new List<T>();
    for (; *p != null; ++p)
    {
        T item = (T)Marshal.PtrToStructure(*p, typeof(T));
        result.Add(item);
    }
    return result;
}

Конечно, вам понадобится явное приведение IntPtr* всякий раз, когда вы это вызываете, но, по крайней мере, в противном случае дублирования кода не будет.

Другие советы

Вы сказали:

Marshal.copy () должен знать размер неуправляемого массива.Я мог бы определить это только с помощью небезопасного кода

Кажется, тебя не хватает Маршал.SizeOf().

Судя по тому, что вы упомянули в посте, этого может быть достаточно для решения вашей проблемы.(Кроме того, параметром вашей функции может быть Object** вместо T**.)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top