Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在仅包含值类型的自定义结构上使用Marshal.SizeOf()方法_C#_.net - Fatal编程技术网

C# 在仅包含值类型的自定义结构上使用Marshal.SizeOf()方法

C# 在仅包含值类型的自定义结构上使用Marshal.SizeOf()方法,c#,.net,C#,.net,我创建了一个由两种值类型组成的简单结构 public struct Identifier { public Guid ID { get; set; } public Byte RequestType { get; set; } } 然后,我使用以下语句调用了自定义结构标识符上的Marshal.SizeOf()方法 Identifier i = new Identifier(); Console.WriteLine(Marshal.SizeOf(i)); // output:

我创建了一个由两种值类型组成的简单结构

public struct Identifier
{
    public Guid ID { get; set; }
    public Byte RequestType { get; set; }
}
然后,我使用以下语句调用了自定义结构
标识符
上的
Marshal.SizeOf()
方法

Identifier i = new Identifier();
Console.WriteLine(Marshal.SizeOf(i));   // output: 20
Console.WriteLine(Marshal.SizeOf(i.GetType()));   // output: 20
为什么
Marshal.SizeOf()
不返回17? 以下说明显示
Guid
对象是16个字节,而Byte
对象是1个字节

Guid g = Guid.NewGuid();
Console.WriteLine(Marshal.SizeOf(g));   // output: 16
Console.WriteLine(Marshal.SizeOf(g.GetType()));   // output: 16

Byte t = 0;
Console.WriteLine(Marshal.SizeOf(t));   // output: 1
Console.WriteLine(Marshal.SizeOf(t.GetType()));   // output: 1

由于对齐原因,当复制到非托管内存时,您的
标识符
结构将填充3个字节。

默认情况下,允许CLR重新排列(对于简单结构,它从不这样做)并根据需要填充结构。这通常是为了在内存中保持它与单词边界对齐

如果您不喜欢此行为并希望更改它,可以按如下方式指定不打包:

[StructLayout(LayoutKind.Sequential,Pack=1)]

如果我在自定义结构上添加一个新字段(例如一个4字节的
int
),我从Marshal.SizeOf()中得到24个字段,因此
Identifier
似乎总是用3个字节填充。事实上,如果我的自定义结构中只有一个字段,那么大小是正确的。这取决于添加填充的字段的时间和位置。一个字节并不总是用3个字节填充。@enzom83:例如,如果在第一个字节字段旁边添加第二个字节字段,则会发现填充减少了一个字节。不是编译器在内存中排列结构,而是CLR。和Marshal.SizeOf返回编组到非托管内存后的大小,而不是CLR安排的托管内存中的大小。@enzom83:假设您有一个
标识符的数组,并且希望访问第二个
Guid
,它不是字节对齐的,因此可能会导致多步读取(读取第一个字,读取第二个字,合并所需位)。通过不提供
StructLayout
您告诉CLR这些细节对您来说并不重要。实际上,结构在托管内存中的排列方式和封送方式可能存在巨大差异。例如,一个
char
需要2个托管字节,但通常封送为1个字节。下面ws-different padding,等等。@dtb:我觉得包含blittable会使答案变得不必要的复杂,但在我的评论中提到了它。
char
不是blittable,因此导致两者不一样,但是
Guid
byte
是。@enzom83:如果你在寻找结构的非托管大小,你会得到应用程序适当的值。如果您正在查找结构的托管大小,可能无法获得该值。但是托管大小实际上没有用处,因此我不担心它。请注意,由于性能原因,blittable类型保持相同,因此具有相同的托管和非托管格式。