c #: универсальное преобразование неуправляемого массива в управляемый список - PullRequest
3 голосов
/ 10 июня 2009

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

Например:

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 () в этом случае не принесло никакой пользы.

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

Ответы [ 2 ]

3 голосов
/ 10 июня 2009

Вы можете сделать разумное предположение, что размер и представление всех указателей одинаковы (не уверен, гарантирует ли это спецификация 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* всякий раз, когда вы вызываете это, но, по крайней мере, в противном случае дублирования кода не будет.

0 голосов
/ 10 июня 2009

Вы сказали:

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

Похоже, вам не хватает Marshal.SizeOf () .

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

...