オブジェクト初期化子とコレクション初期化子 (C# プログラミング ガイド)Object and Collection Initializers (C# Programming Guide)

C# では、1 つの命令文でオブジェクトまたはコレクションをインスタンス化し、1 つのステートメントでメンバーを割り当てることができます。C# lets you instantiate an object or collection and perform member assignments in a single statement.

オブジェクト初期化子Object initializers

オブジェクト初期化子を使用すると、オブジェクトの作成時にアクセスできるフィールドまたはプロパティに、コンストラクターを呼び出して代入ステートメントを使用しなくても、値を割り当てることができます。Object initializers let you assign values to any accessible fields or properties of an object at creation time without having to invoke a constructor followed by lines of assignment statements. オブジェクト初期化子の構文では、コンストラクターの引数を指定することも、引数 (およびかっこ構文) を省略することもできます。The object initializer syntax enables you to specify arguments for a constructor or omit the arguments (and parentheses syntax). 以下の例では、名前付きの型である Cat でオブジェクト初期化子を使用する方法と、既定のコンストラクターを呼び出す方法を示します。The following example shows how to use an object initializer with a named type, Cat and how to invoke the default constructor. Cat クラス内で自動実装プロパティが使用されています。Note the use of auto-implemented properties in the Cat class. 詳細については、「自動実装プロパティ」を参照してください。For more information, see Auto-Implemented Properties.

public class Cat
{
    // Auto-implemented properties.
    public int Age { get; set; }
    public string Name { get; set; }

    public Cat()
    {
    }

    public Cat(string name)
    {
        this.Name = name;
    }
}
Cat cat = new Cat { Age = 10, Name = "Fluffy" };
Cat sameCat = new Cat("Fluffy"){ Age = 10 };

オブジェクト初期化子の構文では、インスタンスを作成できます。その後、新規作成されたオブジェクトは、割り当てられたプロパティと共に、割り当ての変数に代入されます。The object initializers syntax allows you to create an instance, and after that it assigns the newly created object, with its assigned properties, to the variable in the assignment.

C# 6 より、オブジェクト初期化子では、フィールドとプロパティを割り当てることに加え、インデクサーを設定できます。Starting with C# 6, object initializers can set indexers, in addition to assigning fields and properties. 次の基底 Matrix クラスをご覧ください。Consider this basic Matrix class:

public class Matrix
{
    private double[,] storage = new double[3, 3];

    public double this[int row, int column]
    {
        // The embedded array will throw out of range exceptions as appropriate.
        get { return storage[row, column]; }
        set { storage[row, column] = value; }
    }
}

次のコードで単位行列を初期化できます。You could initialize the identity matrix with the following code:

var identity = new Matrix
{
    [0, 0] = 1.0,
    [0, 1] = 0.0,
    [0, 2] = 0.0,

    [1, 0] = 0.0,
    [1, 1] = 1.0,
    [1, 2] = 0.0,

    [2, 0] = 0.0,
    [2, 1] = 0.0,
    [2, 2] = 1.0,
};

アクセス可能なセッターが含まれるアクセス可能なインデクサーを、引数の数や種類と関係なく、オブジェクト初期化子で式の 1 つとして使用できます。Any accessible indexer that contains an accessible setter can be used as one of the expressions in an object initializer, regardless of the number or types of arguments. インデックス引数は代入の左側となり、値は式の右側となります。The index arguments form the left side of the assignment, and the value is the right side of the expression. たとえば、IndexersExample に適切なインデクサーが指定されている場合、以下はすべて有効になります。For example, these are all valid if IndexersExample has the appropriate indexers:

var thing = new IndexersExample {
    name = "object one",
    [1] = '1',
    [2] = '4',
    [3] = '9',
    Baz = Math.PI,
    ['C',4] = "Middle C"
}

上記のコードをコンパイルするには、IndexersExample 型に次のメンバーを指定する必要があります。For the preceding code to compile, the IndexersExample type must have the following members:

public string name;
public double Size { set { ... }; }
public char this[int i] { set { ... }; }
public string this[char c, int i] {  set { ... }; }
}

オブジェクト初期化子と匿名型Object Initializers with anonymous types

オブジェクト初期化子は、どのような場合にも使うことができますが、LINQLINQ クエリ式で使うと特に有用です。Although object initializers can be used in any context, they are especially useful in LINQLINQ query expressions. クエリ式では、次の宣言に示すように、オブジェクト初期化子を使うことによってのみ初期化できる匿名型が頻繁に使われます。Query expressions make frequent use of anonymous types, which can only be initialized by using an object initializer, as shown in the following declaration.

var pet = new { Age = 10, Name = "Fluffy" };  

匿名型を使うと、LINQLINQ クエリ式の select 句によって元のシーケンスのオブジェクトを値と形状が元とは異なるオブジェクトに変換できます。Anonymous types enable the select clause in a LINQLINQ query expression to transform objects of the original sequence into objects whose value and shape may differ from the original. この方法は、シーケンス内の各オブジェクトの情報の一部のみを保存する場合に便利です。This is useful if you want to store only a part of the information from each object in a sequence. 次の例は、製品オブジェクト (p) に多くのフィールドおよびメソッドが含まれており、製品名および単価を含むオブジェクトのシーケンスを作成することにのみ関心があることを想定しています。In the following example, assume that a product object (p) contains many fields and methods, and that you are only interested in creating a sequence of objects that contain the product name and the unit price.

var productInfos =
    from p in products
    select new { p.ProductName, p.UnitPrice };

このクエリが実行されると、productInfos 変数には、次の例に示す foreach ステートメントでアクセスできるオブジェクトのシーケンスが格納されます。When this query is executed, the productInfos variable will contain a sequence of objects that can be accessed in a foreach statement as shown in this example:

foreach(var p in productInfos){...}  

作成される匿名型内の各オブジェクトには、2 つのパブリック プロパティがあります。これらのプロパティには、元のオブジェクトのプロパティまたはフィールドと同じ名前が付けられます。Each object in the new anonymous type has two public properties that receive the same names as the properties or fields in the original object. 匿名型を作成するときにフィールドの名前を変更することもできます。次の例では、フィールド UnitPrice の名前が Price に変更されます。You can also rename a field when you are creating an anonymous type; the following example renames the UnitPrice field to Price.

select new {p.ProductName, Price = p.UnitPrice};  

コレクション初期化子Collection initializers

コレクション初期化子を使うと、IEnumerable を実装するコレクション型を初期化するときに 1 つ以上の要素の初期化子を指定でき、適切なシグネチャの Add をインスタンス メソッドまたは拡張メソッドとして使用できます。Collection initializers let you specify one or more element initializers when you initialize a collection type that implements IEnumerable and has Add with the appropriate signature as an instance method or an extension method. 要素の初期化子は、単純な値、式またはオブジェクト初期化子です。The element initializers can be a simple value, an expression, or an object initializer. コレクション初期化子を使用すると、呼び出しを複数回指定する必要がなくなります。コンパイラによって呼び出しが自動的に追加されるためです。By using a collection initializer, you do not have to specify multiple calls; the compiler adds the calls automatically.

2 つの単純なコレクション初期化子を次の例に示します。The following example shows two simple collection initializers:

List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };  
List<int> digits2 = new List<int> { 0 + 1, 12 % 3, MakeInt() };  

次のコレクション初期化子は、前の例で定義されている Cat クラスのオブジェクトをオブジェクト初期化子を使用して初期化します。The following collection initializer uses object initializers to initialize objects of the Cat class defined in a previous example. 個々のオブジェクト初期化子は、かっこで囲まれ、コンマで区切られています。Note that the individual object initializers are enclosed in braces and separated by commas.

List<Cat> cats = new List<Cat>
{
    new Cat{ Name = "Sylvester", Age=8 },
    new Cat{ Name = "Whiskers", Age=2 },
    new Cat{ Name = "Sasha", Age=14 }
};

コレクションの Add メソッドで許容されている場合、コレクション初期化子の要素として null を指定できます。You can specify null as an element in a collection initializer if the collection's Add method allows it.

List<Cat> moreCats = new List<Cat>
{
    new Cat{ Name = "Furrytail", Age=5 },
    new Cat{ Name = "Peaches", Age=4 },
    null
};

コレクションがインデックスを読み取り/書き込みできる場合は、インデックス付きの要素を指定できます。You can specify indexed elements if the collection supports read / write indexing.

var numbers = new Dictionary<int, string>
{
    [7] = "seven",
    [9] = "nine",
    [13] = "thirteen"
};

上記のサンプルの場合、Item[TKey] を呼び出して値を設定するコードが生成されます。The preceding sample generates code that calls the Item[TKey] to set the values. C# 6 より、次の構文を使用し、ディクショナリやその他の連想コンテナーを初期化できます。Beginning with C# 6, you can initialize dictionaries and other associative containers using the following syntax. インデクサー構文の代わりに、括弧と代入によって 1 つのオブジェクトと複数の値が処理されていることにご注目ください。Notice that instead of indexer syntax, with parentheses and an assignment, it uses an object with multiple values:

var moreNumbers = new Dictionary<int, string>
{
    {19, "nineteen" },
    {23, "twenty-three" },
    {42, "forty-two" }
};

この初期化子の例では、Add(TKey, TValue) を呼び出し、3 つの項目をディクショナリに追加しています。This initializer example calls Add(TKey, TValue) to add the three items into the dictionary. 連想コレクションを初期化するこれら 2 つの異なる方法には、コンパイラによって生成されるメソッド呼び出しにより、動作にわずかな違いがあります。These two different ways to initialize associative collections have slightly different behavior because of the method calls the compiler generates. いずれの場合も Dictionary クラスが使用されます。Both variants work with the Dictionary class. 他の型の場合、パブリック API に基づいて、いずれかのみサポートされることがあります。Other types may only support one or the other based on their public API.

使用例Examples

次の例では、オブジェクトの概念とコレクション初期化子の概念が組み合わさっています。The following example combines the concepts of object and collection initializers.

public class InitializationSample
{
    public class Cat
    {
        // Auto-implemented properties.
        public int Age { get; set; }
        public string Name { get; set; }

        public Cat() { }

        public Cat(string name)
        {
            Name = name;
        }
    }

    public static void Main()
    {
        Cat cat = new Cat { Age = 10, Name = "Fluffy" };
        Cat sameCat = new Cat("Fluffy"){ Age = 10 };

        List<Cat> cats = new List<Cat>
        {
            new Cat { Name = "Sylvester", Age = 8 },
            new Cat { Name = "Whiskers", Age = 2 },
            new Cat { Name = "Sasha", Age = 14 }
        };

        List<Cat> moreCats = new List<Cat>
        {
            new Cat { Name = "Furrytail", Age = 5 },
            new Cat { Name = "Peaches", Age = 4 },
            null
        };

        // Display results.
        System.Console.WriteLine(cat.Name);

        foreach (Cat c in cats)
            System.Console.WriteLine(c.Name);

        foreach (Cat c in moreCats)
            if (c != null)
                System.Console.WriteLine(c.Name);
            else
                System.Console.WriteLine("List element has null value.");
    }
    // Output:
    //Fluffy
    //Sylvester
    //Whiskers
    //Sasha
    //Furrytail
    //Peaches
    //List element has null value.
}

次の例のオブジェクトは IEnumerable を実装します。このオブジェクトには Add メソッドと複数のパラメーターが含まれ、Add メソッドのシグネチャに対応するリスト項目ごとにコレクション初期化子と複数の要素を使用します。The following example shows an object that implements IEnumerable and contains an Add method with multiple parameters, It uses a collection initializer with multiple elements per item in the list that correspond to the signature of the Add method.

    public class FullExample
    { 
        class FormattedAddresses : IEnumerable<string>
        {
            private List<string> internalList = new List<string>();
            public IEnumerator<string> GetEnumerator() => internalList.GetEnumerator();

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => internalList.GetEnumerator();

            public void Add(string firstname, string lastname, 
                string street, string city, 
                string state, string zipcode) => internalList.Add(
                $@"{firstname} {lastname}
{street}
{city}, {state} {zipcode}"
                );
        }

        public static void Main()
        {
            FormattedAddresses addresses = new FormattedAddresses()
            {
                {"John", "Doe", "123 Street", "Topeka", "KS", "00000" },
                {"Jane", "Smith", "456 Street", "Topeka", "KS", "00000" }
            };

            Console.WriteLine("Address Entries:");

            foreach (string addressEntry in addresses)
            {
                Console.WriteLine("\r\n" + addressEntry);
            }
        }

        /*
         * Prints:
         
            Address Entries:

            John Doe
            123 Street
            Topeka, KS 00000

            Jane Smith
            456 Street
            Topeka, KS 00000
         */
    }

Add メソッドでは、次の例で示すように、params キーワードを使用して可変数個の引数を受け取ることができます。Add methods can use the params keyword to take a variable number of arguments, as shown in the following example. この例では、インデクサーのカスタム実装と、インデクサーを使用したコレクションの初期化を示しています。This example also demonstrates the custom implementation of an indexer to initialize a collection using indexes.

public class DictionaryExample
{ 
    class RudimentaryMultiValuedDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, List<TValue>>>
    {
        private Dictionary<TKey, List<TValue>> internalDictionary = new Dictionary<TKey, List<TValue>>();

        public IEnumerator<KeyValuePair<TKey, List<TValue>>> GetEnumerator() => internalDictionary.GetEnumerator();

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => internalDictionary.GetEnumerator();

        public List<TValue> this[TKey key]
        {
            get => internalDictionary[key];
            set => Add(key, value);
        }

        public void Add(TKey key, params TValue[] values) => Add(key, (IEnumerable<TValue>)values);

        public void Add(TKey key, IEnumerable<TValue> values)
        {
            if (!internalDictionary.TryGetValue(key, out List<TValue> storedValues))
                internalDictionary.Add(key, storedValues = new List<TValue>());

            storedValues.AddRange(values);
        }
    }

    public static void Main()
    {
        RudimentaryMultiValuedDictionary<string, string> rudimentaryMultiValuedDictionary1
            = new RudimentaryMultiValuedDictionary<string, string>()
            {
                {"Group1", "Bob", "John", "Mary" },
                {"Group2", "Eric", "Emily", "Debbie", "Jesse" }
            };
        RudimentaryMultiValuedDictionary<string, string> rudimentaryMultiValuedDictionary2
            = new RudimentaryMultiValuedDictionary<string, string>()
            {
                ["Group1"] = new List<string>() { "Bob", "John", "Mary" },
                ["Group2"] = new List<string>() { "Eric", "Emily", "Debbie", "Jesse" }
            };
        RudimentaryMultiValuedDictionary<string, string> rudimentaryMultiValuedDictionary3
            = new RudimentaryMultiValuedDictionary<string, string>()
            {
                {"Group1", new string []{ "Bob", "John", "Mary" } },
                { "Group2", new string[]{ "Eric", "Emily", "Debbie", "Jesse" } }
            };

        Console.WriteLine("Using first multi-valued dictionary created with a collection initializer:");

        foreach (KeyValuePair<string, List<string>> group in rudimentaryMultiValuedDictionary1)
        {
            Console.WriteLine($"\r\nMembers of group {group.Key}: ");

            foreach (string member in group.Value)
            {
                Console.WriteLine(member);
            }
        }

        Console.WriteLine("\r\nUsing second multi-valued dictionary created with a collection initializer using indexing:");

        foreach (KeyValuePair<string, List<string>> group in rudimentaryMultiValuedDictionary2)
        {
            Console.WriteLine($"\r\nMembers of group {group.Key}: ");

            foreach (string member in group.Value)
            {
                Console.WriteLine(member);
            }
        }
        Console.WriteLine("\r\nUsing third multi-valued dictionary created with a collection initializer using indexing:");

        foreach (KeyValuePair<string, List<string>> group in rudimentaryMultiValuedDictionary3)
        {
            Console.WriteLine($"\r\nMembers of group {group.Key}: ");

            foreach (string member in group.Value)
            {
                Console.WriteLine(member);
            }
        }
    }

    /*
     * Prints:
     
        Using first multi-valued dictionary created with a collection initializer:

        Members of group Group1:
        Bob
        John
        Mary

        Members of group Group2:
        Eric
        Emily
        Debbie
        Jesse

        Using second multi-valued dictionary created with a collection initializer using indexing:

        Members of group Group1:
        Bob
        John
        Mary

        Members of group Group2:
        Eric
        Emily
        Debbie
        Jesse

        Using third multi-valued dictionary created with a collection initializer using indexing:

        Members of group Group1:
        Bob
        John
        Mary

        Members of group Group2:
        Eric
        Emily
        Debbie
        Jesse
     */
}

関連項目See also