Dan*_*röm 6 .net c# memory-management
GCHandle.Alloc拒绝使用包含"十进制"数据类型的结构来固定数组,但同时使用"double"工作正常.这是什么原因,我能以某种方式解决它吗?
我知道我可以使用unsafe/fixed来获取指向数组的指针,但这不适用于泛型.:-(
完整示例代码以演示此问题.第一个Alloc工作,但第二个失败了
对象包含非原始或非blittable数据.
public struct X1
{
public double X;
}
public struct X2
{
public decimal X;
}
Run Code Online (Sandbox Code Playgroud)
现在试试这个:
var x1 = new[] {new X1 {X = 42}};
var handle1 = GCHandle.Alloc(x1, GCHandleType.Pinned); // Works
var x2 = new[] { new X2 { X = 42 } };
var handle2 = GCHandle.Alloc(x2, GCHandleType.Pinned); // Fails
Run Code Online (Sandbox Code Playgroud)
Han*_*ant 19
var handle2 = GCHandle.Alloc(x2, GCHandleType.Pinned);
Run Code Online (Sandbox Code Playgroud)
运行时会假设您要打电话handle.AddrOfPinnedObject().当然,你没有理由分配钉扎手柄.返回一个非托管指针,一个IntPtr在C#中.与托管指针不同,这是您使用fixed关键字获得的类型.
它还假设您要将此指针传递给关注值大小和表示的代码.但是否则无法注入转换,该代码将直接在IntPtr上派对.这需要值类型为blittable,这是一个令人讨厌的词,这意味着可以简单地直接解释或复制值中的字节而无需任何转换,并且使用IntPtr的代码将能够识别该值的相当大的几率正确.
这是一些.NET类型的问题,例如bool类型是臭名昭着的.只需用bool而不是十进制尝试相同的代码,并注意你将得到完全相同的异常.System.Boolean是一个非常困难的互操作类型,没有主导标准描述它应该是什么样子.它是C语言和Winapi中的4个字节,COM自动化中的2个字节,C++中的1个字节以及其他几种语言.换句话说,"其他代码"试图解释1字节.NET值的可能性相当小.不可预测的大小特别令人讨厌,这会抛弃所有后续成员.
与System.Decimal大致相同,没有广泛采用的标准来确定其内部格式.许多语言根本不支持它,特别是C和C++,如果你用这种语言编写代码,那么你需要使用一个库.哪个可能使用IEEE 754-2008小数,但这是一个约翰尼 - 最近来的并且受到"太多标准"问题的困扰.在编写CLI规范时,IEEE 854-1987标准已经出现,但它被广泛忽略.今天仍然是一个问题,很少有处理器设计支持小数,我只知道PowerPC.
简而言之,您需要创建自己的blittable类型来存储小数..NET设计者决定使用COM Automation Currency类型来实现System.Decimal,这是当时的主流实现,这要归功于Visual Basic.这种情况极不可能改变,因为过多的代码依赖于内部格式,使得这些代码最容易兼容和快速:
public struct X2 {
private long nativeDecimal;
public decimal X {
get { return decimal.FromOACurrency(nativeDecimal); }
set { nativeDecimal = decimal.ToOACurrency(value); }
}
}
Run Code Online (Sandbox Code Playgroud)
你也可以考虑uint []和Decimal.Get/SetBits(),但我认为它不太可能更快,你必须尝试.