简体   繁体   English

当声明为函数的返回值时,C# 结构是否曾被装箱?

[英]Is a C# struct ever boxed when declared as the return value of a function?

A simple question, but I haven't found a definitive answer on Stack Overflow.一个简单的问题,但我还没有在 Stack Overflow 上找到明确的答案。

    struct MyStruct { int x, y, z; }

    MyStruct GetMyStruct() => new MyStruct();

    static void Main()
    {
        var x = GetMyStruct();      // can boxing/unboxing ever occur?
    }

Is a C# struct (value type) always copied to the stack when returned from a function, no matter how large it might be?从函数返回时, C#结构(值类型)是否总是复制到堆栈中,无论它有多大? The reason I'm unsure is that for some instruction sets other than MSIL (such as x86), a return value usually needs to fit into a processor register, and the stack is not directly involved.我不确定的原因是,对于 MSIL 以外的某些指令集(例如 x86),返回值通常需要放入处理器寄存器中,并且不直接涉及堆栈。

If so, is it the call site that pre-allocates space on the CLR stack for the (expected) value return type?如果是这样,它是否是在CLR堆栈上为(预期的)值返回类型预先分配空间的调用站点?

[edit: summary of replies:] For the intent of the original question, the answer is no; [编辑:答复摘要:] 对于原始问题的意图,答案是否定的; the CLR will never (silently) box a struct just for the purpose of sending it as a return value. CLR永远不会(悄悄地)为了将结构体作为返回值发送而将其装箱。

It is a heavy implementation detail of the JIT compiler.它是 JIT 编译器的重要实现细节。 In general, if the struct is small enough and has simple members then its gets returned in CPU registers.通常,如果结构足够小并且具有简单的成员,那么它会在 CPU 寄存器中返回。 If it gets too big then the calling code reserves enough space on the stack and passes a pointer to that space as an extra hidden argument.如果它变得太大,则调用代码在堆栈上保留足够的空间并将指向该空间的指针作为额外的隐藏参数传递。

It will never be boxed, unless the return type of the method is object of course.它永远不会被装箱,除非方法的返回类型当然是对象

Fwiw: this is also the reason that the debugger cannot display the return value of the function in the Autos window. Fwiw:这也是调试器无法在Autos窗口中显示函数返回值的原因。 Painful sometimes.有时很痛苦。 But the debugger doesn't get enough metadata from the JIT compiler to know exactly where to find the value.但是调试器没有从 JIT 编译器获得足够的元数据来准确地知道在哪里可以找到值。 Edit: fixed in VS2013.编辑:在 VS2013 中修复。

A struct is boxed whenever you want to treat it as an object , so if you call Func and assign the result to object it will be boxed.每当您想将结构体视为object ,它都会被装箱,因此如果您调用Func并将结果分配给 object 它将被装箱。

Eg doing this例如这样做

 object o = Func();

will yield the following IL将产生以下 IL

L_0000: call valuetype TestApp.foo TestApp.Program::Func()
L_0005: box TestApp.foo
L_000a: stloc.0 

which shows that the return value is boxed, because we assign it to a reference of the type object .这表明返回值是装箱的,因为我们将它分配给类型object的引用。

If you assign it to a variable of type Foo it isn't boxed and thus it is copied and the value is stored on the stack.如果你将它分配给一个Foo类型的变量,它不会被装箱,因此它被复制并且值存储在堆栈中。

Also, boxing wouldn't really help you here since it would involve creating an object to represent the value of the struct, and the values are effectively copied during the boxing operation.此外,装箱在这里不会真正帮助您,因为它会涉及创建一个对象来表示结构的值,并且在装箱操作期间这些值会被有效地复制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM