オブジェクト初期化子の利用 - new の後ろに中括弧がある記述

C#でnewの直後に中括弧があり、中括弧内で(プロパティ名)=(値)がカンマ区切りで記述される書式について紹介します。

概要

newの直後に中括弧があり、中括弧内で(プロパティ名)=(値)がカンマ区切りで記述されるコードはオブジェクト初期化子と呼ばれる記述です。
補足
newの直後の中括弧の中身が値のみのカンマ区切りで記述される、コレクション初期化子についてはこちらの記事を参照してください。

オブジェクトの初期化子

new 演算子により、オブジェクトのインスタンスを作成した直後にインスタンスのメンバ変数に値を設定することができます。

書式

書式は次の通りです。
new クラス名(){ プロパティ名1 = 値, プロパティ名2 = 値, .... プロパティ名n = 値};

コンストラクタの括弧は省略できるため下記の書式も利用可能です。
new クラス名{ プロパティ名1 = 値, プロパティ名2 = 値, .... プロパティ名n = 値};

プログラム例 : オブジェクト初期化子

Windows Formアプリケーションを作成します。

UI

下図のUIを作成します。ボタンを2つテキストボックスを1つ配置します。

コード

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ObjectInitializer
{
  public partial class FormSimpleObjectInitializer : Form
  {
    MyItem mi;

    public FormSimpleObjectInitializer()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      mi = new MyItem { name="ぺんぎんクッキー", price=280, count=8 };
      
      //こちらの記述でもOK
      //mi = new MyItem() { name="ぺんぎんクッキー", price=280, count=8 };
    }

    private void button2_Click(object sender, EventArgs e)
    {
      textBox1.Text = string.Format("{0} : {1:g} / {2:d}",mi.name, mi.price, mi.count);
    }
  }
}
クラスのコードは下記になります。
MyItem.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ObjectInitializer
{
  public class MyItem
  {
    public string name;
    public decimal price;
    public int count;
  }
}

解説

下記の行がオブジェクト初期化子を利用したコードになります。オブジェクトのnewの直後に{~}のブロックを記述し、その中でメンバ変数の値を設定できます。下記のコードではクラスの、name, price, count のメンバ変数に値を設定しています。
  mi = new MyItem { name="ぺんぎんクッキー", price=280, count=8 };

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。


[button1]をクリックし、その後[button2]をクリックします。クラスのメンバ変数に設定された内容がテキストボックスに表示されます。

参考 (オブジェクト初期化子を利用しない場合)

オブジェクト初期化子を利用しない場合のコードは下記なります。オブジェクト初期化子を利用しないため、オブジェクトのメンバ変数に対してひとつづつ代入をして値を設定しています。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ObjectInitializer
{
  public partial class FormSimpleObjectInitializer : Form
  {
    MyItem mi;

    public FormSimpleObjectInitializer()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      mi = new MyItem();
      mi.name = "ぺんぎんクッキー";
      mi.price = 280;
      mi.count = 8;
    }

    private void button2_Click(object sender, EventArgs e)
    {
      textBox1.Text = string.Format("{0} : {1:g} / {2:d}",mi.name, mi.price, mi.count);
    }
  }
}

匿名オブジェクトの初期化子

先の例では、クラスのオブジェクトに対してオブジェクトの初期化子を利用する例を紹介しました。オブジェクトの初期化子は匿名オブジェクトに対しても利用できます。匿名オブジェクトの場合の例を紹介します。

プログラム例: 匿名オブジェクトの初期化子

Windows Formアプリケーションを作成します。

UI

下図のUIを作成します。フォームにボタンとテキストボックスを1つずつ配置します。

コード

下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ObjectInitializer
{
  public partial class FormAnonymousObjectInitializer : Form
  {
    public FormAnonymousObjectInitializer()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      var myItem = new { name = "らくだサブレ", price = 550, count = 8, weight = 0.25 };

      textBox1.Text += "名称 : " + myItem.name+"\r\n";
      textBox1.Text += "価格 : " + myItem.price.ToString() + "\r\n";
      textBox1.Text += "在庫 : " + myItem.count.ToString() + "\r\n";
      textBox1.Text += string.Format("重量 : {0:f2}\r\n", myItem.weight);
    }
  }
}

解説

下記のコードが初期化子を利用して匿名オブジェクトの初期化をするコードです。
このコードにより、myItem に name, price, count, weight のメンバ変数を持つ匿名のオブジェクトが作成され設定されます。初期化子のブロックで代入処理が記述されていますので、myItemオブジェクトのnameに"らくだサブレ"、priceに550、countに3、weightに0.25の値が初期値として設定されます。
  var myItem = new { name = "らくだサブレ", price = 550, count = 8, weight = 0.25 };

myItemオブジェクトのメンバ変数の値を参照して、メンバ変数の値をテキストボックスに表示するコードが下記です。
  textBox1.Text += "名称 : " + myItem.name+"\r\n";
  textBox1.Text += "価格 : " + myItem.price.ToString() + "\r\n";
  textBox1.Text += "在庫 : " + myItem.count.ToString() + "\r\n";
  textBox1.Text += string.Format("重量 : {0:f2}\r\n", myItem.weight);

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。


[button1]をクリックします。匿名オブジェクトが作成され、オブジェクトに設定された値がテキストボックスに表示されます。

LINQと組み合わせて匿名オブジェクトの初期化子を利用する

先の例では、匿名オブジェクトの初期化子を利用するコードを紹介しましたが、匿名オブジェクトのvar 宣言はローカル変数としての宣言しかできないため、あまり実用的なコードではありません。匿名オブジェクトの初期化子はLINQと組み合わせて利用する場合があります。

プログラム例 : LINQと組み合わせた匿名オブジェクトの初期化子

UI

下図のUIを作成します。フォームにボタンとテキストボックスを1つずつ配置します。

コード

下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ObjectInitializer
{
  public partial class FormAnonymousObjectInitializerLinq : Form
  {
    List<MyItem> MyList = new List<MyItem>();

    public FormAnonymousObjectInitializerLinq()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      MyList.Add(new MyItem() { name = "ぺんぎんクッキー", price = 380, count=4 });
      MyList.Add(new MyItem() { name = "らくだサブレ", price = 260, count = 7 });
      MyList.Add(new MyItem() { name = "あひるスフレ", price = 160, count = 3 });
      MyList.Add(new MyItem() { name = "くじらキャンディ", price = 80, count = 12 });
      MyList.Add(new MyItem() { name = "かるがもケーキ", price = 580, count = 2 });
    }

    private void button2_Click(object sender, EventArgs e)
    {
      var items = from i in MyList select new { i.name};

      foreach (var t in items) {
        textBox1.Text += string.Format("{0}\r\n", t.name);
      }
    }
  }
}

解説

button1のクリックにより、MyListにMyItemオブジェクトの要素を挿入します。下記コードがオブジェクトを作成し値を設定するコードです。先に紹介した「オブジェクト初期化子」を利用して値を設定しています。
new MyItem() { name = "ぺんぎんクッキー", price = 380, count=4 }

[button2]クリックイベントでの下記のコードがLINQのコードとなります。LINQの動作の詳細についてはこちらの記事を参照してください。
  var items = from i in MyList select new { i.name};

一般的なLINQでは、下記のコードの記述になります。この場合itemsにはMyListの要素であるMyItemオブジェクトの IEnumerable オブジェクトが格納されます。
  var items = from i in MyList select i;

今回のコードでは、select の後ろが new { i.name} となっているため、itemsにMyItemオブジェクトが格納されるのではなく、nameメンバのみのオブジェクトが格納されます。LINQの結果でMyItemオブジェクトの不要なメンバ変数を含めず、必要なメンバ変数の値のみを取得するため、このような記述ができます。

foreach ループによりLINQで取得したIEnumerable オブジェクトに含まれるすべての要素をテキストボックスに表示します。LINQでMyItemオブジェクトのnameメンバのみを匿名オブジェクトで返す記述をしているため、name以外のメンバは含まれません。
  foreach (var t in items) {
    textBox1.Text += string.Format("{0}\r\n", t.name);
  }

下記コードはコンパイルエラーとなります。
  foreach (var t in items) {
    textBox1.Text += string.Format("{0}, {1:g}\r\n", t.name, t.price);
  }

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。


[button1]をクリックし、その後[button2]をクリックします。MyListに挿入した要素のnameの値がテキストボックスに表示されます。

補足

LINQで返されるオブジェクトのメンバ名を変更したい場合は下記の書式が利用できます。MyItemクラスでは count という名称のメンバ変数ですが、LINQで返される匿名オブジェクトではppというメンバ名に変更したい場合の例です。オブジェクト初期化子のブロック内で pp=i.count と記述することで、元のオブジェクトのメンバ変数名を別の名称に変更できます。
  private void button3_Click(object sender, EventArgs e)
  {
    var items = from i in MyList select new { i.name, pp = i.count};

    foreach (var t in items) {
      textBox1.Text += string.Format("{0} {1:d}\r\n", t.name, t.pp);
    }
  }

上記コードの実行結果は下図となります。([button1]クリック後に[button3]をクリックした場合。)


著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2017-09-25
iPentec all rights reserverd.