Мммм ... Я выложу код, который, вероятно, вам не нужен: -)
Я использую последний компилятор (C # 7.0) ( nuget )плюс небезопасная библиотека ( nuget ).
Дело в том, что я не хочу выполнять маршалирование путем копирования структуры Unmanaged2d
, а также не хочу копировать массив.Я хочу использовать их "на месте".Я буду использовать ref return
плюс некоторые Unsafe.As*
методы для чтения одного MyPodStruct
, когда его спросят, и двумерный индексатор, чтобы скрыть все.к сожалению, Unsafe.As*
требует ключевое слово unsafe
, потому что его методы принимают void*
вместо принятия IntPtr
.
[StructLayout(LayoutKind.Sequential, Size = 16)]
public struct MyPodStruct // Plain Old Data
{
public double a;
public double b;
};
[StructLayout(LayoutKind.Sequential)]
public struct Unmanaged2d
{
public IntPtr arr;
public int n;
public int m;
public unsafe ref MyPodStruct this[int x, int y]
{
get
{
if (x < 0 || x >= n)
{
throw new ArgumentOutOfRangeException(nameof(x));
}
if (y < 0 || y >= m)
{
throw new ArgumentOutOfRangeException(nameof(y));
}
IntPtr ptr = Marshal.ReadIntPtr(arr, x * sizeof(IntPtr));
IntPtr ptr2 = ptr + y * 16; // 16 == sizeof(MyPodStruct)
return ref Unsafe.AsRef<MyPodStruct>(ptr2.ToPointer());
}
}
}
unsafe_Init2d(ref unsafeRes, n, m);
// We increase all the values of a and b, just to show that we can!
for (int i = 0; i < u.n; i++)
{
for (int j = 0; j < u.m; j++)
{
u[i, j].a += 10;
u[i, j].b++;
}
}
// We print them
for (int i = 0; i < u.n; i++)
{
Console.WriteLine(string.Join(";", Enumerable.Range(0, u.m).Select(x => string.Format($"({u[i, x].a},{u[i, x].b})"))));
}
В качестве идентификатора кажется, что использование IntPtr
делает "небезопасным""код" сейф "не одобряется.Смотрите, например, здесь , где запрос на перегрузку на Span<T>(void*)
, который принимает Span<T>(IntPtr)
и был закрыт, потому что:
Мы хотим, чтобы операции с указателями были явной операциейс указателями, а не прятать их за IntPtr, которые, как правило, дают людям ложное чувство безопасности.
и здесь .
В общем, что вы хотитеdo можно сделать с некоторыми Marshal.ReadIntPtr
плюс BitConverter.Int64BitsToDouble(Marshal.ReadInt64(...))
, например:
[StructLayout(LayoutKind.Sequential)]
public struct Unmanaged2d
{
public IntPtr arr;
public int n;
public int m;
public static MyPodStruct[,] Fill2dResult()
{
Unmanaged2d unsafeRes = new Unmanaged2d();
//unsafe_Init2d(ref unsafeRes, n, m); // I have n, m from elsewhere
//unsafe_Fill2dResult(ref unsafeRes);
MyPodStruct[,] res = new MyPodStruct[unsafeRes.n, unsafeRes.m];
for (int i = 0; i < unsafeRes.n; i++)
{
IntPtr row = Marshal.ReadIntPtr(unsafeRes.arr, i * IntPtr.Size);
for (int j = 0, offset = 0; j < unsafeRes.m; j++)
{
// Automatic marshaling of MyPodStruct
// res[i, j] = Marshal.PtrToStructure<MyPodStruct>(row + j * (sizeof(double) + sizeof(double)));
// Manual marshaling
// a
long temp1 = Marshal.ReadInt64(row, offset);
double dbl1 = BitConverter.Int64BitsToDouble(temp1);
offset += sizeof(double);
// b
long temp2 = Marshal.ReadInt64(row, offset);
double dbl2 = BitConverter.Int64BitsToDouble(temp2);
offset += sizeof(double);
res[i, j] = new MyPodStruct { a = dbl1, b = dbl2 };
}
}
//unsafe_Free2d(ref unsafeRes);
return res;
}
}
Технически этот код не содержит ничего, что составляет unsafe
, но он настолько же небезопасен, как и ваш код.
Ах ... а в C # то, что у вас есть в C, называется зубчатым массивом.Это массив массивов (массив уровней указателей первого уровня, которые указывают на множество элементов второго уровня).Это не многомерный массив.