Yur*_*rik 5 c# pointers unsafe unmanaged
在 C# 中,我需要将 T[] 写入流,理想情况下没有任何额外的缓冲区。我有一个动态代码,可以将 T[](其中 T 是无对象结构)转换为 void* 并将其修复在内存中,并且效果很好。当流是一个文件时,我可以使用本机 Windows API 直接传递 void *,但现在我需要写入一个采用 byte[] 的通用 Stream 对象。
问题:任何人都可以提出一种创建虚拟数组对象的黑客方法,该对象实际上没有任何堆分配,而是指向一个已经存在(和固定)的堆位置?
这是我需要的伪代码:
void Write(Stream stream, T[] buffer)
{
fixed( void* ptr = &buffer ) // done with dynamic code generation
{
int typeSize = sizeof(T); // done as well
byte[] dummy = (byte[]) ptr; // <-- how do I create this fake array?
stream.Write( dummy, 0, buffer.Length*typeSize );
}
}
Run Code Online (Sandbox Code Playgroud)
更新:
我fixed(void* ptr=&buffer)在这篇文章中深入描述了如何做。我总是可以创建一个字节 [],在内存中修复它并从一个指针到另一个指针进行不安全的字节复制,然后将该数组发送到流,但我希望避免不必要的额外分配和复制。
不可能的? 进一步思考后,byte[] 在堆中有一些元数据,包括数组维度和元素类型。简单地将引用(指针)作为 byte[] 传递给 T[] 可能不起作用,因为块的元数据仍然是 T[] 的元数据。并且即使元数据的结构相同,T[] 的长度也会比 byte[] 小很多,因此托管代码对 byte[] 的任何后续访问都会产生错误的结果。
功能请求@ Microsoft Connect 请投票支持此请求,希望 MS 会倾听。
这种代码永远无法以通用方式工作。它依赖于一个硬性假设,即 T 的内存布局是可预测的且一致的。仅当 T 是简单值类型时才是如此。暂时忽略字节序。如果 T 是引用类型,那么您就死定了,您将复制永远无法反序列化的跟踪句柄,您必须为 T 提供结构约束。
但这还不够,结构类型也不可复制。即使它们没有引用类型字段,您也无法限制它们。内部布局由JIT编译器决定。它会随意交换字段,选择一个字段正确对齐且结构值采用最小存储大小的字段。您要序列化的值只能由使用完全相同的 CPU 架构和 JIT 编译器版本运行的程序正确读取。
框架中已经有很多类可以完成您正在做的事情。最接近的匹配是 .NET 4.0 MemoryMappedViewAccessor 类。它需要执行相同的工作,使原始字节在内存映射文件中可用。其中的主力是 System.Runtime.InteropServices.SafeBuffer 类,使用 Reflector 来看看。不幸的是,您不能只复制该类,它依赖于 CLR 来进行转换。话又说回来,距离上市还剩一周的时间。
| 归档时间: |
|
| 查看次数: |
6433 次 |
| 最近记录: |