在函数调用中创建新对象

时间:2011-10-25 14:24:29

标签: c#

我想知道创建新对象作为方法(或构造函数调用)的一部分是否安全

如下面的拙劣例子:

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);
    }
}

创建像这样的临时对象不赞成? 是否正确清理了创建的新对象。

5 个答案:

答案 0 :(得分:6)

这没有错。

在发布模式下,为对象创建变量应该最终编译为相同的IL(免责声明:我没有检查过)。

答案 1 :(得分:3)

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是一个基于堆栈的虚拟机,因此参数从左到右被压入堆栈(因此堆栈中的最后一项是最右边的参数) 。在这种情况下,由于上一次操作,只有一个参数并且它已经在堆栈中,因此我们准备调用我们的方法。

如果我们将这与我们进行以下修改时产生的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
}

除了声明本地化的方法的开头,唯一的区别是创建stloc.0和我们对ldloc.0的调用之间的IglooDoSomething调用。这是什么?

stloc.0是一个从堆栈中弹出最后一项并将其存储在第0个本地的指令。注意,此时我们不再有正确的堆栈来调用DoSomething(我们需要我们的Igloo实例位于堆栈的顶部)这是ldloc.0的用途 - 它推动第0个本地(后面)到堆栈。基本上这两个指令是我们的任务。

请注意,当JITer将其编译为机器代码时,这两个语句几乎肯定会被优化掉。

答案 2 :(得分:2)

如果您创建一个Windows窗体项目而不是一个控制台项目,您将在program.cs中找到以下行:

Application.Run(new FormMain());

因此,MS似乎也与Windows窗体项目的默认值完全相同。

答案 3 :(得分:1)

这在c#中是安全和标准的,所有垃圾收集器一旦无法访问就会收集这些对象。

答案 4 :(得分:1)

是的,是的。该对象将在以后自动删除。