web-dev-qa-db-ja.com

オブジェクトの初期化によるプロパティの設定かどうか:違いはありますか?

ここに簡単な質問があります:これの間に(パフォーマンス)違いはありますか:

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

この

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

より多くのプロパティを持つより大きなオブジェクトを想像することができます。

36
Philippe Lavoie

最初のメソッド( オブジェクト初期化子 を使用)が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 
}

2番目はこれを与えます:

.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#コードについては、以下を参照してください。

パフォーマンス測定では、オブジェクト初期化構文を使用した場合のパフォーマンスがわずかに向上するだけで、非常に類似した結果が示されます。

 1秒あたりのメソッド反復
 ObjectInitializer880万
 SetProperties860万

パフォーマンスのテストに使用したコード:

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();
    }
}
44
Mark Byers

注目に値するもう1つのことはこれです:

コンストラクターで例外を処理できない場合、TypeInitializationExceptionが発生します。それはそれほど悪くはないように思われるかもしれませんが、真実はそれが問題の本当の原因を隠し、追跡するのを難しくしているということです。

一方、オブジェクトを使用する場合initializer、コンストラクターの各プロパティを個別に呼び出すoutside、スローされた例外は非常に明確で非常に明白になります:TypeInitializationExceptionによってマスクされません。

一般に、コンストラクターで例外をスローすることはお勧めできません。このシナリオを回避したい場合は、初期化子を使用してください。

9
Mike Hofer

他の人が言っているように、いいえ、違いはありません。最初の例は、実際にはこれらの引数にコンストラクターを使用していないことに注意してください。これは、C#3.0で導入された「オブジェクト初期化」言語機能を使用しています。呼び出されるコンストラクターは、2番目の例と同様に、デフォルトのパラメーターなしコンストラクターです。

2つの例は、実際には同じILコードにコンパイルされ、正確に同じことを行います。最初の例は、タスクを<opinion>より簡単で表現力豊かな方法で</ opinion>達成するための単なる構文糖衣です。

2
David

いいえ。最初の方法は.NET3.5の新機能ですが、2番目の例は以前のバージョンのC#用です。

他の回答が示しているように、パフォーマンスに関しては大きな違いはありません。

ただし、2つのパラメーターを持つイニシャライザーを使用してオブジェクトを作成することは、あなたのように思えます意図を述べてくださいそれを使用している人には、「これらの2つのパラメーターは機能の最小値です。クラスの」(ただし、その意図を表現する正しい方法は、コンストラクターを使用することです)。

私はイニシャライザ構文をこのように考える傾向がありますが、多かれ少なかれ単なる構文糖衣です。コードでは、両方の構文を組み合わせて使用​​しています。しかし、繰り返しになりますが、それは私の個人的なスタイルです。

0