在函数调用中创建新对象
本文关键字:对象 新对象 函数调用 创建 | 更新日期: 2023-09-27 18:12:26
我想知道创建新对象作为方法(或构造函数调用)的一部分是否安全
例如下面这个痉挛的例子:
public class Igloo
{
public int i = 5;
}
public class Program
{
static void Main(string[] args)
{
DoSomething(new Igloo());
}
private static void DoSomething(Igloo i)
{
Debug.WriteLine(i.i);
}
}
创建这样的临时对象是否不受欢迎?创建的新对象是否得到了正确的清理?
这没什么不对。
在发布模式下,为对象创建变量应该最终编译到相同的IL(免责声明:我没有检查过)。
如果您创建的是Windows窗体项目而不是控制台项目,您将在program.cs中发现以下行:
Application.Run(new FormMain());
所以似乎MS也做了完全相同的默认windows窗体项目
SLaks是对的——这是完全正确的,并且在所有意图和目的上都与以下操作相同:
Igloo igloo = new Igloo();
DoSomething(igloo);
在这两种情况下,一旦Igloo
实例被传递给DoSomething
方法-此时,该实例不再从Main
方法中访问,使得该实例在DoSomething
方法完成收集后具有收集资格。
如果我们想更详细地了解发生了什么,请查看IL:
.method private hidebysig static
void Main (string[] args) cil managed
{
// Method begins at RVA 0x2060
// Code size 13 (0xd)
.maxstack 8
.entrypoint
IL_0000: nop
IL_0001: newobj instance void ConsoleApplication1.Igloo::.ctor()
IL_0006: call void ConsoleApplication1.Program::DoSomething(class ConsoleApplication1.Igloo)
IL_000b: nop
IL_000c: ret
}
解释这是什么意思;我们看到,在IL_0001
上,我们创建了Igloo
的一个新实例——由于CLR是一个基于堆栈的虚拟机,该指令将对该实例的引用推入堆栈。下一条指令是对DoSomething
的调用——CLR又是一个基于堆栈的虚拟机,所以参数从左到右被压入堆栈(因此堆栈上的最后一项是最右边的参数)。在这种情况下,只有1个参数,并且作为最后一次操作的结果已经在堆栈上,因此我们准备调用我们的方法。
如果我们将其与进行以下修改时产生的IL进行比较:
Igloo igloo = new Igloo();
DoSomething(igloo);
我们只能看到几个重要的区别:
.method private hidebysig static
void Main (string[] args) cil managed
{
// Method begins at RVA 0x2060
// Code size 15 (0xf)
.maxstack 1
.entrypoint
.locals init (
[0] class ConsoleApplication1.Igloo igloo
)
IL_0000: nop
IL_0001: newobj instance void ConsoleApplication1.Igloo::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: call void ConsoleApplication1.Program::DoSomething(class ConsoleApplication1.Igloo)
IL_000d: nop
IL_000e: ret
}
除了在方法的开始声明局部变量之外,唯一的区别是在创建Igloo
和调用DoSomething
之间调用stloc.0
和ldloc.0
。这是什么?
stloc.0
是一个将最后一项从堆栈中弹出并将其存储在第0个本地的指令。注意,在这一点上,我们不再有正确的堆栈来调用DoSomething
(我们需要我们的Igloo
实例位于堆栈的顶部),这就是ldloc.0
的作用-它将第0个本地(返回)推到堆栈上。这两条指令就是我们的赋值指令。
请注意,当它被JITer编译成机器代码时,这两个语句几乎肯定会被优化出来。
这在c#中是安全且标准的,所有的垃圾收集器都会在这些对象不可访问时收集它们。
可以。该对象稍后将自动删除。