C#: 관리되지 않은 배열을 관리하는 목록으로 일반적으로 변환
문제
동적으로 합의 된 배열을 통해 데이터를 반환하는 일련의 기본 기능을 다루고 있습니다. 함수는 참조 포인터를 입력으로 가져간 다음 결과 배열을 가리 킵니다.
예를 들어:
typedef struct result
{
//..Some Members..//
}
int extern WINAPI getInfo(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 ()는 관리되지 않는 배열의 크기를 알아야합니다. 안전하지 않은 코드를 사용하여 이것을 결정할 수있었습니다
당신이 놓친 것 같습니다 Marshal.sizeof ().
게시물에서 언급 한 바에 따르면 문제를 해결하기에 충분할 수 있습니다. (또한 함수의 매개 변수는 t ** 대신 객체 **이어야 할 수도 있습니다.)