是否通过对象初始化设置属性:有什么区别吗?

发布于 2024-10-17 13:14:26 字数 532 浏览 1 评论 0原文

之间有任何(性能)​​差异吗

Person person = new Person()
{
  Name = "Philippe",
  Mail = "[email protected]",
};

这是一个简单的问题: this :和 this

Person person = new Person();
person.Name = "Philippe";
person.Mail = "[email protected]";

?您可以想象具有更多属性的更大对象。

Here's a simple question : Is there any (performance) difference between this :

Person person = new Person()
{
  Name = "Philippe",
  Mail = "[email protected]",
};

and this

Person person = new Person();
person.Name = "Philippe";
person.Mail = "[email protected]";

You can imagine bigger object with more properties.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

天赋异禀 2024-10-24 13:14:26

它们几乎完全相同,除了第一种方法(使用 对象初始值设定项 ) 仅适用于 C# 3.0 及更高版本。任何性能差异都很小,不值得担心。

它们生成几乎相同的 IL 代码。第一个给出了这个:

.method private hidebysig instance void ObjectInitializer() cil managed
{
    .maxstack 2
    .locals init (
        [0] class Person person,
        [1] class Person <>g__initLocal0)
    L_0000: newobj instance void Person::.ctor()
    L_0005: stloc.1 
    L_0006: ldloc.1 
    L_0007: ldstr "Philippe"
    L_000c: callvirt instance void Person::set_Name(string)
    L_0011: ldloc.1 
    L_0012: ldstr "[email protected]"
    L_0017: callvirt instance void Person::set_Mail(string)
    L_001c: ldloc.1 
    L_001d: stloc.0 
    L_001e: ldloc.0 
    L_001f: callvirt instance string [mscorlib]System.Object::ToString()
    L_0024: pop 
    L_0025: ret 
}

第二个给出了这个:

.method private hidebysig instance void SetProperties() cil managed
{
    .maxstack 2
    .locals init (
        [0] class Person person)
    L_0000: newobj instance void Person::.ctor()
    L_0005: stloc.0 
    L_0006: ldloc.0 
    L_0007: ldstr "Philippe"
    L_000c: callvirt instance void Person::set_Name(string)
    L_0011: ldloc.0 
    L_0012: ldstr "[email protected]"
    L_0017: callvirt instance void Person::set_Mail(string)
    L_001c: ldloc.0 
    L_001d: callvirt instance string [mscorlib]System.Object::ToString()
    L_0022: pop 
    L_0023: ret 
}

正如您所看到的,生成了几乎相同的代码。请参阅下面我编译的确切 C# 代码。

性能测量显示了非常相似的结果,但使用对象初始值设定项语法的性能改进非常小:

Method               Iterations per second
ObjectInitializer    8.8 million
SetProperties        8.6 million

我用于测试性能的代码:

using System;

class Person
{
    public string Name { get; set; }
    public string Mail { get; set; }
}

class Program
{
    private void ObjectInitializer()
    {
        Person person = new Person()
        {
            Name = "Philippe",
            Mail = "[email protected]",
        };
        person.ToString();
    }

    private void SetProperties()
    {
        Person person = new Person();
        person.Name = "Philippe";
        person.Mail = "[email protected]";
        person.ToString();
    }

    private const int repetitions = 100000000;

    private void Time(Action action)
    {
        DateTime start = DateTime.UtcNow;
        for (int i = 0; i < repetitions; ++i)
        {
            action();
        }
        DateTime end = DateTime.UtcNow;
        Console.WriteLine(repetitions / (end - start).TotalSeconds);
    }

    private void Run()
    {
        Time(ObjectInitializer);
        Time(SetProperties);
        Console.WriteLine("Finished");
        Console.ReadLine();
    }

    private static void Main()
    {
        new Program().Run();
    }
}

They are almost exactly equivalent except that the first method (using an object initializer) only works in C# 3.0 and newer. Any performance difference is only minor and not worth worrying about.

They produce almost identical IL code. The first gives this:

.method private hidebysig instance void ObjectInitializer() cil managed
{
    .maxstack 2
    .locals init (
        [0] class Person person,
        [1] class Person <>g__initLocal0)
    L_0000: newobj instance void Person::.ctor()
    L_0005: stloc.1 
    L_0006: ldloc.1 
    L_0007: ldstr "Philippe"
    L_000c: callvirt instance void Person::set_Name(string)
    L_0011: ldloc.1 
    L_0012: ldstr "[email protected]"
    L_0017: callvirt instance void Person::set_Mail(string)
    L_001c: ldloc.1 
    L_001d: stloc.0 
    L_001e: ldloc.0 
    L_001f: callvirt instance string [mscorlib]System.Object::ToString()
    L_0024: pop 
    L_0025: ret 
}

The second gives this:

.method private hidebysig instance void SetProperties() cil managed
{
    .maxstack 2
    .locals init (
        [0] class Person person)
    L_0000: newobj instance void Person::.ctor()
    L_0005: stloc.0 
    L_0006: ldloc.0 
    L_0007: ldstr "Philippe"
    L_000c: callvirt instance void Person::set_Name(string)
    L_0011: ldloc.0 
    L_0012: ldstr "[email protected]"
    L_0017: callvirt instance void Person::set_Mail(string)
    L_001c: ldloc.0 
    L_001d: callvirt instance string [mscorlib]System.Object::ToString()
    L_0022: pop 
    L_0023: ret 
}

As you can see, nearly identical code is generated. See below for the exact C# code I compiled.

Performance measurements show very similar results with a very small performance improvement for using the object initializer syntax:

Method               Iterations per second
ObjectInitializer    8.8 million
SetProperties        8.6 million

Code I used for testing the performance:

using System;

class Person
{
    public string Name { get; set; }
    public string Mail { get; set; }
}

class Program
{
    private void ObjectInitializer()
    {
        Person person = new Person()
        {
            Name = "Philippe",
            Mail = "[email protected]",
        };
        person.ToString();
    }

    private void SetProperties()
    {
        Person person = new Person();
        person.Name = "Philippe";
        person.Mail = "[email protected]";
        person.ToString();
    }

    private const int repetitions = 100000000;

    private void Time(Action action)
    {
        DateTime start = DateTime.UtcNow;
        for (int i = 0; i < repetitions; ++i)
        {
            action();
        }
        DateTime end = DateTime.UtcNow;
        Console.WriteLine(repetitions / (end - start).TotalSeconds);
    }

    private void Run()
    {
        Time(ObjectInitializer);
        Time(SetProperties);
        Console.WriteLine("Finished");
        Console.ReadLine();
    }

    private static void Main()
    {
        new Program().Run();
    }
}
濫情▎り 2024-10-24 13:14:26

另外一件值得注意的事情是:

如果您无法在构造函数中处理异常,您将收到 TypeInitializationException。虽然这看起来可能并没有那么糟糕,但事实是它掩盖了问题的真正原因,并且使追踪变得更加困难。

另一方面,如果您使用对象初始化程序,则您将在构造函数外部单独调用每个属性,并且任何抛出的异常都将非常清晰且明显:它们不会被 TypeInitializationException 掩盖。

一般来说,在构造函数中抛出异常是一个坏主意。如果您想避免这种情况,请使用初始化程序。

One additional thing worth noting is this:

If you fail to handle an exception in your constructor, you'll get a TypeInitializationException. While that may not seem so bad, the truth is that it conceals the real cause of the problem, and makes it harder to track down.

If, on the other hand, you use an object initializer, you're invoking each property individually outside of the constructor, and any thrown exceptions will be very clear and very evident: they won't be masked by the TypeInitializationException.

In general, it's a bad idea to throw exceptions in a constructor. If you want to avoid that scenario, go with the initializer.

︶ ̄淡然 2024-10-24 13:14:26

正如其他人所说,不,没有区别。请注意,第一个示例实际上并未对这些参数使用构造函数。它使用 C# 3.0 中引入的“对象初始值设定项”语言功能。就像第二个示例一样,被调用的构造函数是默认的无参数构造函数。

这两个示例实际上编译为(几乎)相同的 IL 代码,并且出于所有意图和目的执行相同的操作。第一个示例只是一个相对较新的语法,以更简单且更具表现力的方式完成任务“意见”。

As others have said, no, there is no difference. Note that the first example isn't actually using a constructor for those arguments. It's using the "object initializer" language feature introduced in C# 3.0. The constructor being called is the default parameterless constructor just like the second example.

The two examples actually compile down to (nearly) the same IL code and for all intents and purposes do the same thing. The first example is just a relatively newer syntax to accomplish the task <opinion>in an easier and more expressive way</opinion>.

三生一梦 2024-10-24 13:14:26

不是。第一种方法是 .NET 3.5 中的新方法,但第二个示例适用于以前版本的 C#。

No. The first way is new in .NET 3.5 but the second example is for previous versions of C#.

祁梦 2024-10-24 13:14:26

正如其他答复所示,性能方面没有显着差异。

然而,在我看来,使用带有 2 个参数的初始化程序创建一个对象就像您向使用它的任何人陈述您的意图,形成一个“契约”:“这 2 个参数是功能的最小值类的”(尽管表达该意图的正确方法是使用构造函数)。

我倾向于以这种方式思考初始化语法,尽管它或多或少只是语法糖。我在代码中混合使用了两种语法。但话又说回来,这就是我的个人风格。

Performance-wise there is no significant difference, as other replies have shown.

However, creating an object using an initializer with 2 parameters seems to me like you state your intent to anyone who is using it, forming a "contract" saying: "these 2 parameters are the minimum for the functionality of the class" (although the correct way to express that intent would be to use a constructor).

I tend to think of the initializer syntax this way, although it's more or less just syntactic sugar. I use a mix of both syntaxes in my code. But then again, that's my personal style.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文