创建对象之间是否存在任何差异,然后将其返回或直接创建并返回?

时间:2015-12-02 14:39:26

标签: c# .net

对不起标题,很难说。请看我的例子。
GetUser1和GetUser2之间有什么区别吗?

class Program
{
    static void Main(string[] args)
    {
        GetUser1();
        GetUser2();
    }

    private static User GetUser1()
    {
        return new User
    {
            Name = "Hello"
    };
    }

    private static User GetUser2()
    {
        User user = new User
        {
            Name = "Hello"
        };
        return user;
    }
}

public class User
{
    public string Name { get; set; }
}

我的一个朋友说;没有区别 但是我这么说;两种方法之间存在差异。 GetUser2正在创建一个不必要的新对象。并且GetUser2有轻微(非常小的)性能错误,因为您正在创建一个新对象......这是什么真相?我该如何研究这个主题?

更新
非常感谢你的回答...所以我继续问;
如果GetUser1和GetUser2之间没有区别,为什么roslyn会像这样编译代码(link);

private static User GetUser1()
{
    return new User {
        Name = "Hello"
    };
}

3 个答案:

答案 0 :(得分:8)

发布模式中编译时没有区别。如果您在调试模式中查看发出的IL,您会注意到在返回对象之前存储和加载变量的附加stloc/ldloc instruction形式的细微差别。

如果你看the generated compiler code,你会得到两个相同的结果:

private static void Main(string[] args)
{
    Program.GetUser1();
    Program.GetUser2();
}
private static User GetUser1()
{
    return new User {
        Name = "Hello"
    };
}
private static User GetUser2()
{
    return new User {
        Name = "Hello"
    };
}

两者都是the generated IL code

.method private hidebysig static 
    class User GetUser1 () cil managed 
{
    // Method begins at RVA 0x2068
    // Code size 17 (0x11)
    .maxstack 8

    IL_0000: newobj instance void User::.ctor()
    IL_0005: dup
    IL_0006: ldstr "Hello"
    IL_000b: callvirt instance void User::set_Name(string)
    IL_0010: ret
} // end of method Program::GetUser1

.method private hidebysig static 
    class User GetUser2 () cil managed 
{
    // Method begins at RVA 0x2068
    // Code size 17 (0x11)
    .maxstack 8

    IL_0000: newobj instance void User::.ctor()
    IL_0005: dup
    IL_0006: ldstr "Hello"
    IL_000b: callvirt instance void User::set_Name(string)
    IL_0010: ret
} // end of method Program::GetUser2

答案 1 :(得分:5)

在没有抖动优化的情况下,调试版本之间存在细微差别,因为冗余没有被删除,因此您可以更轻松地检查调试器中的值。

发布版本将删除它,抖动优化也可以这样做,因此在调试情况之外,两者是相同的。

答案 2 :(得分:2)

  

两种方法之间存在差异。 GetUser2正在创建一个不必要的新对象。并且GetUser2有轻微(非常小的)性能错误,因为您正在创建一个新对象。

两种方法都在创建一个新对象。使用中间变量(User user)的方法只增加了:变量,它只是指向同一对象的指针。

一旦方法超出范围,变量就不再存在。

即使在调试模式下,堆栈中另外一个变量的差异也绝对可以忽略不计。