C# - 在没有任何新内存分配的情况下将任何不安全的非托管类型转换为托管类型 - 在内存中保持相同的大小
C# - convert any unsafe unmanaged type to managed type without any new memory allocation - keeping the same size in memory
我想将 ushort 数组转换为 short 数组,而无需在 C# 核心中分配新内存。
还可以将任何类型,例如 byte[] 转换为 short[],反之亦然 - 转换需要在内存中为源和目标保持相同的大小
在 C 中有 "union" 语法,可以通过多种类型转换引用该类型 - 我没有找到 C# 的任何等效项(仅适用于非基本类型)。
一种方法是这样编码
ushort[] res = new ushort[1024 * 1024 * 1024];
short[] s = new short[1024 * 1024 * 1024];
Buffer.BlockCopy(s, 0, res, 0, s.Length * 2);
...但是,我不会分配 's' 值 - 它占用太多内存,可能会导致内存泄漏。
我使用的另一种选择是使用不安全模式。
代码:
unsafe
{
ushort[] res = new ushort[1024*1024*1024]; // large allocating
fixed (ushort* ss = &res[0])
{
IntPtr ps = (IntPtr)ss;
short[] s0 = (short[])Marshal.PtrToStructure(ps, typeof(short[]));
}
}
运行 进入异常。
No parameterless constructor defined for this object.
...
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean wrapExceptions, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean wrapExceptions, Boolean skipCheckThis, Boolean fillCache)
at System.Runtime.InteropServices.Marshal.PtrToStructure(IntPtr ptr, Type structureType)
如何在不需要分配新内存的情况下最终转换那个 1G 字节的大数组?
我可以将数组类型从非托管类型转换为托管类型吗?
如果可能的话,我更喜欢使用不安全模式。
经过深入搜索,我找到了一个解决方案,我会参与(并编辑此post),但它有一个问题,描述如下:
如果数组大小相同,那段代码工作得很好 - 有一个新问题 - 我如何解决不同数组基类型大小的问题(即 short[] vs byte []) ?
我唯一无法从 short[] 转换为 byte[]。
这适用于 C# 核心以及 C# .NET
首先,创建一个 class:
public static class MyConverter
{
public static unsafe T GetInstance<T>(IntPtr pointer)
{
try
{
var fakeInstance = default(T);
TypedReference typedReference = __makeref(fakeInstance);
*(IntPtr*)(&typedReference) = pointer;
T instance = (T) __refvalue(typedReference,T);
return instance;
}
catch
{
return default(T);
}
}
}
并且可以像这样在代码中使用它:
ushort[] x = new ushort[1024];
GCHandle handle1 = GCHandle.Alloc(x);
IntPtr px = (IntPtr)handle1;
x[0] = 1;
x[1] = 2;
x[2] = 3;
short[] s = MyConverter.GetInstance<short[]>(px);
该解决方案将 ushort[] 转换为 short[] 而不会浪费任何内存。
谢谢。
您可以像这样轻松转换:(ushort[])(object)myShortArray
。 CLR 允许这样做。
只允许大小相同的原始数组元素类型。
在其他情况下,您可以使用 Span
将内存视为不同类型。
Span<int> asInts = MemoryMarshal.Cast<byte, int>(asBytes);
我想将 ushort 数组转换为 short 数组,而无需在 C# 核心中分配新内存。
还可以将任何类型,例如 byte[] 转换为 short[],反之亦然 - 转换需要在内存中为源和目标保持相同的大小
在 C 中有 "union" 语法,可以通过多种类型转换引用该类型 - 我没有找到 C# 的任何等效项(仅适用于非基本类型)。
一种方法是这样编码
ushort[] res = new ushort[1024 * 1024 * 1024];
short[] s = new short[1024 * 1024 * 1024];
Buffer.BlockCopy(s, 0, res, 0, s.Length * 2);
...但是,我不会分配 's' 值 - 它占用太多内存,可能会导致内存泄漏。
我使用的另一种选择是使用不安全模式。
代码:
unsafe
{
ushort[] res = new ushort[1024*1024*1024]; // large allocating
fixed (ushort* ss = &res[0])
{
IntPtr ps = (IntPtr)ss;
short[] s0 = (short[])Marshal.PtrToStructure(ps, typeof(short[]));
}
}
运行 进入异常。
No parameterless constructor defined for this object.
...
at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean wrapExceptions, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean wrapExceptions, Boolean skipCheckThis, Boolean fillCache)
at System.Runtime.InteropServices.Marshal.PtrToStructure(IntPtr ptr, Type structureType)
如何在不需要分配新内存的情况下最终转换那个 1G 字节的大数组?
我可以将数组类型从非托管类型转换为托管类型吗?
如果可能的话,我更喜欢使用不安全模式。
经过深入搜索,我找到了一个解决方案,我会参与(并编辑此post),但它有一个问题,描述如下:
如果数组大小相同,那段代码工作得很好 - 有一个新问题 - 我如何解决不同数组基类型大小的问题(即 short[] vs byte []) ?
我唯一无法从 short[] 转换为 byte[]。
这适用于 C# 核心以及 C# .NET
首先,创建一个 class:
public static class MyConverter
{
public static unsafe T GetInstance<T>(IntPtr pointer)
{
try
{
var fakeInstance = default(T);
TypedReference typedReference = __makeref(fakeInstance);
*(IntPtr*)(&typedReference) = pointer;
T instance = (T) __refvalue(typedReference,T);
return instance;
}
catch
{
return default(T);
}
}
}
并且可以像这样在代码中使用它:
ushort[] x = new ushort[1024];
GCHandle handle1 = GCHandle.Alloc(x);
IntPtr px = (IntPtr)handle1;
x[0] = 1;
x[1] = 2;
x[2] = 3;
short[] s = MyConverter.GetInstance<short[]>(px);
该解决方案将 ushort[] 转换为 short[] 而不会浪费任何内存。
谢谢。
您可以像这样轻松转换:(ushort[])(object)myShortArray
。 CLR 允许这样做。
只允许大小相同的原始数组元素类型。
在其他情况下,您可以使用 Span
将内存视为不同类型。
Span<int> asInts = MemoryMarshal.Cast<byte, int>(asBytes);