【问题标题】:Setting properties via object initialization or not : Any difference ?是否通过对象初始化设置属性:有什么区别吗?
【发布时间】:2011-06-25 19:11:09
【问题描述】:

这是一个简单的问题:这之间是否有任何(性能)​​差异:

Person person = new Person()
{
  Name = "Philippe",
  Mail = "phil@phil.com",
};

还有这个

Person person = new Person();
person.Name = "Philippe";
person.Mail = "phil@phil.com";

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

【问题讨论】:

  • 同样值得查看this answer 来回答类似的问题。

标签: c# performance properties setter object-initialization


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    正如其他回复所显示的那样,性能方面没有显着差异。

    但是,在我看来,使用具有 2 个参数的初始化程序创建一个对象就像您向任何使用它的人说明您的意图,形成一个“合同”,说:“这 2 个参数是最小值为了类的功能”(尽管表达这种意图的正确方法是使用构造函数)。

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

    【讨论】:

      【解决方案3】:

      还有一点值得注意的是:

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

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

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

      【讨论】:

      • +1 让我意识到对象初始化只发生在构造函数运行之后。
      【解决方案4】:

      它们几乎完全相同,只是第一种方法(使用object initializer)仅适用于 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 "phil@phil.com"
          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 "phil@phil.com"
          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# 代码,请参见下文。

      性能测量显示非常相似的结果,但使用对象初始化器语法的性能改进非常小:

      每秒方法迭代次数 ObjectInitializer 880 万 SetProperties 860 万

      我用来测试性能的代码:

      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 = "phil@phil.com",
              };
              person.ToString();
          }
      
          private void SetProperties()
          {
              Person person = new Person();
              person.Name = "Philippe";
              person.Mail = "phil@phil.com";
              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();
          }
      }
      

      【讨论】:

      • 好吧,只要你有 3.0 编译器,你就可以在为 .net 2.0 编写的代码中使用它。
      • 所以用对象初始化器来做这件事要注意。有没有首选的方式?
      • 个人意见:对于简单的对象或者只用静态值初始化,像这个例子,初始化块是可以的——干净易读。如果我必须分配很多属性或使用变量,我倾向于使用标准分配选项。仅仅因为如果它在 OI 块内因任何原因(空对象等)失败,则更难找出它失败的地方。使用标准分配它会告诉你问题出在哪里。
      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-07
        • 2021-10-25
        • 1970-01-01
        • 2010-10-18
        • 2017-05-13
        • 2010-12-06
        • 1970-01-01
        • 2022-08-14
        相关资源
        最近更新 更多