Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/256.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#struct是否曾经装箱?_C#_Struct_Return Value_Boxing_Value Type - Fatal编程技术网

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

当声明为函数的返回值时,C#struct是否曾经装箱?,c#,struct,return-value,boxing,value-type,C#,Struct,Return Value,Boxing,Value Type,一个简单的问题,但我还没有找到关于堆栈溢出的确切答案 struct MyStruct { int x, y, z; } MyStruct GetMyStruct() => new MyStruct(); static void Main() { var x = GetMyStruct(); // can boxing/unboxing ever occur? } 当从函数返回时,C#结构(值类型)是否总是复制到堆栈中,

一个简单的问题,但我还没有找到关于堆栈溢出的确切答案

    struct MyStruct { int x, y, z; }

    MyStruct GetMyStruct() => new MyStruct();

    static void Main()
    {
        var x = GetMyStruct();      // can boxing/unboxing ever occur?
    }
当从函数返回时,C#结构(值类型)是否总是复制到堆栈中,无论它有多大?我不确定的原因是,对于MSIL以外的某些指令集(如x86),通常需要将返回值放入处理器寄存器,而堆栈并不直接涉及

如果是,是调用站点在CLR堆栈上为(预期)值返回类型预先分配了空间吗


[编辑:答复摘要:]对于原始问题的意图,答案是否定的;CLR永远不会(无提示地)为将结构作为返回值发送而装箱。

每当您想将结构作为
对象处理时,它都会装箱,因此如果调用
Func
并将结果分配给对象,它就会装箱

例如,这样做

 object o = Func();
将产生以下IL

L_0000: call valuetype TestApp.foo TestApp.Program::Func()
L_0005: box TestApp.foo
L_000a: stloc.0 
这表明返回值已装箱,因为我们将其分配给类型为
对象
的引用

如果将其分配给类型为
Foo
的变量,则不会将其装箱,因此会复制该变量并将值存储在堆栈上


此外,装箱在这里并没有真正的帮助,因为它需要创建一个对象来表示结构的值,并且在装箱操作期间会有效地复制这些值

这是JIT编译器的一个繁重的实现细节。通常,如果结构足够小并且具有简单的成员,那么它将在CPU寄存器中返回。如果它变得太大,则调用代码在堆栈上保留足够的空间,并将指向该空间的指针作为额外的隐藏参数传递

它永远不会被装箱,除非方法的返回类型是object


Fwiw:这也是调试器无法在Autos窗口中显示函数返回值的原因。有时很痛苦。但是调试器没有从JIT编译器中获得足够的元数据来准确地知道在哪里找到值。编辑:在VS2013中修复。

调用站点必须在堆栈上分配适当数量的字节这一事实是.NET设计指南建议
struct
s在理想情况下不应大于16字节的原因。@Richard:您有该信息的来源吗?是的,其中包含16字节的建议,但并没有说这是因为呼叫站点必须分配数据。我会努力追踪我读到这篇文章的具体来源。@JimMischel根据答案,如果你想保证并确保避免BLT大型结构,您应该显式地使用
ref
out
而不是返回结构。如果值类型的返回是ever(您使用的“ever”似乎意味着有时如果发生,它不是无条件的)装箱,这意味着当我们将返回赋给值类型变量时,会隐式取消装箱,这似乎效率低下。我对MSIL和CLR不太了解,所以我在这里帮不了你。不管怎样,我可以知道是什么引起了你的问题吗?@Bliz面食:当我意识到我错误地认为“ref”(和“out”)关键字导致了值类型的装箱(事实并非如此)时,我原来的问题实际上变得毫无意义。为了避免这种情况,我打算“返回”结构。但是,一旦我记住“ref”并没有框选值类型,使用out参数就成了一个选项。我的值类型的大小目前是4+IntPtr.size字节,并且数十万个这样的结构被非常密集地操作。