如何在C#中绕过校验创建无效decimal值以模拟C库返回结果?
解决方法:强行创建指定字节的无效decimal
背景
你在调用C库时,必须传入decimal类型让C函数填充字节(存储日期时间数字字符的字节数组),但该decimal并非有效值。现在需要Mock这个委托,需要绕过decimal的有效性校验,直接写入指定字节。
方法1:使用unsafe代码直接操作内存
通过unsafe代码固定decimal变量的内存地址,将目标字节数组直接复制到该内存区域,绕过构造函数的校验。
首先确保项目已启用允许不安全代码(在项目属性→生成→勾选“允许不安全代码”)。
示例代码:
// 模拟C函数返回的字节数组:对应字符串"2001020304050678"的ASCII字节 byte[] targetBytes = System.Text.Encoding.ASCII.GetBytes("2001020304050678"); // 初始化decimal变量 decimal dummyDecimal = 0M; unsafe { fixed (byte* decimalPtr = &System.BitConverter.GetBytes(dummyDecimal)[0]) { // 将目标字节复制到decimal的内存中(decimal占16字节,这里只覆盖前16个字节) for (int i = 0; i < targetBytes.Length && i < 16; i++) { *(decimalPtr + i) = targetBytes[i]; } } } // 此时dummyDecimal已被填充指定字节,可用于Mock委托调用
方法2:使用Marshal类操作非托管内存
通过非托管内存中转,将字节数组写入内存后转换为decimal,无需启用unsafe代码。
示例代码:
// 模拟C函数返回的字节数组 byte[] targetBytes = System.Text.Encoding.ASCII.GetBytes("2001020304050678"); // 分配非托管内存(decimal占16字节) IntPtr unmanagedPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(16); try { // 将字节数组复制到非托管内存 System.Runtime.InteropServices.Marshal.Copy(targetBytes, 0, unmanagedPtr, targetBytes.Length); // 将非托管内存转换为decimal decimal mockDecimal = (decimal)System.Runtime.InteropServices.Marshal.PtrToStructure(unmanagedPtr, typeof(decimal)); // 使用mockDecimal进行委托Mock } finally { // 释放非托管内存 System.Runtime.InteropServices.Marshal.FreeHGlobal(unmanagedPtr); }
注意事项
- 这两种方法创建的
decimal是无效的,仅能用于内存字节读取,不能进行任何算术运算或格式化操作,否则会抛出异常。 - 确保目标字节数组长度不超过16字节(
decimal的固定大小),超出部分会被忽略。
内容的提问来源于stack exchange,提问作者Helena
相关产品推荐
相关产品推荐

