问题 在C#中新建一个空结构有什么作用?


如果你已经声明了一个结构:

struct EmptyResult
{
}

创建类型变量的结果是什么 EmptyResult 在一个实例?

public Foo()
{
    EmptyResult result;
}

您是否期望在堆栈上进行分配,还是实际上是无操作?


9135
2018-06-06 15:22


起源

我希望编译器能够优化它。在Foo的那条线上放一个断点,看它是否命中? - Sayse
<没关系> ...... - James
如果您创建了类型的变量,它将被优化掉 int。也许更好的例子是将结构传递给函数。 - David Heffernan
这让我想知道,存储的值和引用类型的类型在哪里,但这是一个不同的问题。 - Jodrell


答案:


C#编译器强制空结构的大小为1个字节。如果你看一下反编译器中的struct,你可以看到这个:

[StructLayout(LayoutKind.Sequential, Size=1)]
private struct EmptyResult
{
}

因此,类或堆栈中该结构的任何实例都将占用1个字节,与实例完全相同 System.Byte 要么 System.SByte


9
2018-06-06 15:27



据推测,它是为了能够获取其地址。 - David Heffernan
您不需要反编译。您可以使用 Marshal.SizeOf(typeof(EmptyResult))。我刚要发布的内容,但速度太慢了。 - David Heffernan
@DavidHeffernan我确定你是对的 - 这样你就可以获取它的地址,但也有两个实例会有不同的地址。有趣的是, Stroustrup提到了关于空C ++结构的问题。 - Matthew Watson
@MatthewWatson:我认为C#有这种行为,因为C ++确实如此,即使C#通常不像C ++那样使用地址作为对象标识符。 - supercat


没有字段的C#结构的大小仍然是1.原因是编译器必须能够使用以下内容获取结构的地址 & 运算符在不安全的代码中。

我希望你的结构类型的处理方式与 byte 类型。


3
2018-06-06 15:46





我认为这是一个堆栈分配,它与非引用类型的工作方式一致。


1
2018-06-06 15:24



但结构的大小是0字节;你如何分配0字节? - Servy
在c ++中,它占用一个字节。 - aquaraga


如果你使用 idlasm.exe 研究il,在你创建一个实例的行 Empty 结构,你会看到:

.maxstack  1
.locals init ([0] valuetype Draft.Empty e)

和定义 Empty 结构是:

.class private sequential ansi sealed beforefieldinit Draft.Empty
       extends [mscorlib]System.ValueType
{
  .pack 0
  .size 1
} // end of class Draft.Empty

如您所见,它在创建时分配1个字节,在定义中,此类型的大小为1。

所以是的;它在堆栈上分配1个字节。

注意:定义 Empty 在发布模式下从已编译的程序集中提取。


1
2018-06-06 15:48



JIT阶段当然可以优化它 - David Heffernan
@DavidHeffernan如果你能解释一下,我会学到一些东西 new Empty().Equals(new Empty()) 返回true。它不需要堆栈上的实际地址吗? (我真的不熟悉JIT工作流程);谢谢 - Kaveh Shahbazian
Equals() 检查结构的值相等。由于没有字段,所以情况就是如此 s1.Equals(s2) 总是 true 对于类型的操作数 EmptyResult。 - David Heffernan
@KavehShahbazian结构 Equals 方法成员等于。这两个成员的所有(零) Empty 对象是相等的,因此两个结构是相等的。它只是默认相等运算符比较引用的引用类型。 - Servy
@Servy Holly Foo!我忘了我在这里处理一个值类型! - Kaveh Shahbazian