C#プログラミング備忘録

C# コンストラクターとオブジェクト初期化子について

C#

C#3.0から使えるようになったオブジェクト初期化子について、まずは以下の簡単なサンプルプログラムを考えてみる。

using System;

namespace CSharpStudy
{
    class Program
    {
        static void Main(string[] args)
        {
            //オブジェクト初期化子によるインスタンスの生成
            Book book = new Book
            {
                title = "坊ちゃん",
                author = "夏目漱石"
            };

            book.ShowBook();

            Console.ReadLine();
        }
    }

    class Book
    {
        public string title;
        public string author;


        public void ShowBook()
        {
            Console.WriteLine("タイトル:{0} 著者:{1} ", title, author);
        }
    }
}

このプログラムの実行結果は以下の通りとなる。実行結果には疑問はない。

タイトル:坊ちゃん 著者:夏目漱石

疑問に思ったのはオブジェクト初期化子という呼び方である。というのも初期化を行うのはあくまでもコンストラクターの仕事だと思うからだ。実際、上のプログラムは以下と等価である。

using System;

namespace CSharpStudy
{
    class Program
    {
        static void Main(string[] args)
        {
            Book book = new Book(); //デフォルトコンストラクターによる初期化
            book.title = "坊ちゃん"; //代入
            book.author = "夏目漱石"; //代入

            book.ShowBook();

            Console.ReadLine();
        }
    }

    class Book
    {
        public string title;
        public string author;


        public void ShowBook()
        {
            Console.WriteLine("タイトル:{0} 著者:{1} ", title, author);
        }
    }
}

Bookインスタンスをデフォルトコンストラクターで初期化した後、メンバー変数のtitleとauthorに値を代入している。ここで以下のようにプログラムを変更してみるとオブジェクト初期化子のメンバー変数への代入の前にデフォルトコンストラクターが呼ばれているのがわかる。

using System;

namespace CSharpStudy
{
    class Program
    {
        static void Main(string[] args)
        {
            //オブジェクト初期化子によるインスタンスの生成
            Book book = new Book
            {
                title = "坊ちゃん",
                author = "夏目漱石"
            };

            book.ShowBook();

            Console.ReadLine();
        }
    }

    class Book
    {
        public string title;
        public string author;

        //デフォルトコンストラクター
        public Book()
        {
            Console.WriteLine("デフォルトコンストラクターの呼び出し");
        }

        public void ShowBook()
        {
            Console.WriteLine("タイトル:{0} 著者:{1} ", title, author);
        }
    }
}

このプログラムの実行結果は以下の通りとなる。

デフォルトコンストラクターの呼び出し
タイトル:坊ちゃん 著者:夏目漱石

初期化を行うのはコンストラクターでオブジェクト初期化子は代入と思える。ちなみに以下のようにデフォルトコンストラクターの自動生成をやめるように引数を伴うコンストラクターを定義するとコンパイルエラーとなる。

using System;

namespace CSharpStudy
{
    class Program
    {
        static void Main(string[] args)
        {
            //オブジェクト初期化子によるインスタンスの生成 <---- コンパイルエラー
            Book book = new Book
            {
                title = "坊ちゃん",
                author = "夏目漱石"
            };

            book.ShowBook();

            Console.ReadLine();
        }
    }

    class Book
    {
        public string title;
        public string author;

        //2つの引数を持つコンストラクター
        public Book(string title, string author)
        {
            this.title = title;
            this.author = author;
        }

        public void ShowBook()
        {
            Console.WriteLine("タイトル:{0} 著者:{1} ", title, author);
        }
    }
}

この場合は以下の通りデフォルトコンストラクターを明示的に定義する必要がある。

using System;

namespace CSharpStudy
{
    class Program
    {
        static void Main(string[] args)
        {
            //オブジェクト初期化子によるインスタンスの生成
            Book book = new Book
            {
                title = "坊ちゃん",
                author = "夏目漱石"
            };

            book.ShowBook();

            Console.ReadLine();
        }
    }

    class Book
    {
        public string title;
        public string author;

        //デフォルトコンストラクター
        public Book()
        {
            Console.WriteLine("デフォルトコンストラクターの呼び出し");
        }

        //2つの引数を持つコンストラクター
        public Book(string title, string author)
        {
            this.title = title;
            this.author = author;
        }

        public void ShowBook()
        {
            Console.WriteLine("タイトル:{0} 著者:{1} ", title, author);
        }
    }
}

追記 

もともとオブジェクト初期化子も匿名型と同様にLINQを実装するために導入された言語拡張のためかもしれない。以下のような書き方が出来るようになっている。

using System;

namespace CSharpStudy
{
    class Program
    {
        static void Main(string[] args)
        {
            //匿名型オブジェクトの初期化
            var book = new { title = "坊ちゃん", author = "夏目漱石"};

            Console.WriteLine("タイトル:{0} 著者:{1} ", book.title, book.author);

            Console.ReadLine();

        }
    }
}

上記の書き方だと名前の付いたクラスを指定せずにnew演算子を使用しているのでtitleもauthorも代入ではなく初期化していると言えそうだ。オブジェクト初期化子という名前の由来はこれかもしれない。

コメント