匿名型とdynamic型を理解しよう!

[C#] 匿名型とdynamic型を理解しよう!

※ 当サイトは広告を含みます。

ここではC#の匿名型dynamic型を学習します。

匿名型(Anonymous type)

匿名型とは、型名が存在しない型を意味します。これは型名が匿名とも言えます。
SNS等で本人特定されないことを匿名性とか言いますが、似てなくもないです。

型の名前が存在しないって意味が分からないと思いますが、本当にそのままです。
メソッド配下など、記述できる場所は限られますが、次のような名無し型を作れます。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      // 匿名型
      var anonymous = new
      {
        Name = "すーぱーはかー",
        Address = "だーくうぇぶ",
      };

      Console.WriteLine($"名前={anonymous.Name}, 住所={anonymous.Address}");
    }
  }
}

ちなみに匿名型の中身は参照型のクラスです。

特に制限もないので、匿名型の配列を記述できたり、匿名型の中に匿名型を記述することもできます。
言語的に不可能な記述をすればビルドエラーになるので、そのときは諦めてください。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      // 匿名型
      var anonymous = new
      {
        Name = "すーぱーはかー",
        Address = "だーくうぇぶ",
        Skills = new[]
        {
          new
          {
            Ability = "F5連打",
          },
          new
          {
            Ability = "きーぼーどくらっしゅ",
          },
        },
      };

      Console.WriteLine($"名前={anonymous.Name}, 住所={anonymous.Address}");

      foreach (var skill in anonymous.Skills)
        Console.WriteLine($"スキル={skill.Ability}");
    }
  }
}

匿名型に記述できるのはプロパティのみ。また、そのプロパティは自動的にgetオンリーになります。
つまり読み取り専用です。よって、後から値を代入することはできません。

加えて、匿名型の内部に記述したプロパティの型は型推論で自動的に決定されます。
この時にnullみたいな型推論が不可能な記述をするとビルドエラーになります。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      // 匿名型
      var anonymous = new
      {
        Name = "すーぱーはかー",
        Address = "だーくうぇぶ",
        Skills = null, // 型推論が不可能なのでビルドエラー
      };

      // 読み取り専用なのでビルドエラー
      anonymous.Address = "ダル";

      Console.WriteLine($"名前={anonymous.Name}, 住所={anonymous.Address}");
    }
  }
}

他にも匿名型自体の型はvar、または後述するdynamicで記述する必要があります。
ただし、基本的にvarしか使いません。dynamicは型の特性上で記述できるだけです。

りさ
りさ

これ何に使うんですか?

管理人
管理人

一瞬だけ使うデータ型に利用する。後はLINQって機能があって、そこで使うことがメイン。
言ってしまうと、初心者向けの機能ではないと思う。あくまで一時的な利用が目的かな。

dynamic型

これは動的型付けと呼ばれる特殊な参照型です。先に伝えると、理解せずに使ったら例外が多発して死にます。

プログラムの世界で動的とは、実行時に何かしらの処理がされることを意味します。
今回は動的型付けなので、実行時に型処理が発生します。逆に言うと、ビルド時のチェックは一切されません。

ここで先程の匿名型をdynamic型で記述してみましょう。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      // dynamic型
      dynamic anonymous = new
      {
        Name = "すーぱーはかー",
        Address = "だーくうぇぶ",
      };

      Console.WriteLine($"名前={anonymous.Name}, 住所={anonymous.Address}");
    }
  }
}

さらにdynamic型では、こんな記述も許されます。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      // dynamic型
      dynamic anonymous = new
      {
        Name = "すーぱーはかー",
        Address = "だーくうぇぶ",
      };

      // Skillsプロパティは存在しない
      Console.WriteLine($"名前={anonymous.Name}, 住所={anonymous.Address}, スキル={anonymous.Skills}");
    }
  }
}

なお、許されるのはビルドが通るって話であって、正常に動作することではありません。
先程のパターンを実行すると例外が発生してプログラムは落ちますが、それが正常動作です。

理由は存在しないプロパティを呼び出してるからです。仮に匿名型で書いた場合はビルドエラーになります。
dynamic型の特徴はビルド時のチェックがされません。そこを実行時に判断するから動的型なんです。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      // dynamic型
      dynamic anonymous = new
      {
        Name = "すーぱーはかー",
        Address = "だーくうぇぶ",
      };

      try
      {
        // Skillsプロパティは存在しない
        Console.WriteLine($"名前={anonymous.Name}, 住所={anonymous.Address}, スキル={anonymous.Skills}");
      }
      catch (Exception e)
      {
        Console.WriteLine(e.Message);
      }
    }
  }
}
りさ
りさ

これこそ何に使うんですか?

管理人
管理人

一時的な型とか、何らかのファイルを解析するときに中身が可変な場合とか。
最初に言った通り、まず初心者にはオススメできない。型への理解が不十分なのに使うのは絶対駄目。

匿名型との違い

人によっては匿名型の亜種に見えますが、dynamic型は根本的に仕組みが異なります。
大きな違いとして、dynamic型はあくまで何らかの型を示す参照型です。
つまり、動的に判断されてるだけであり、その先には真っ当な型が存在してます。

よって、匿名型では不可能だったメソッドやフィールドでも参照が可能です。


namespace Sample
{
  internal class Program
  {
    internal class Data
    {
      public string Field;

      public string Property { get; set; }

      public void Method()
      {
        Console.WriteLine($"Field={this.Field}, Property={this.Property}");
      }
    }

    static void Main(string[] args)
    {
      dynamic data = new Data();

      data.Field = "field";       // フィールド参照
      data.Property = "property"; // プロパティ参照
      data.Method();              // メソッド参照
    }
  }
}

このように、正しく存在する限りは何でも呼び出せます。駄目なら実行時に例外になります。
また、ビルド時点では存在有無が不明なため、IDEIntelliSense(予測入力)は機能しません。

さらにdynamic型は立派な型なので、次のようにメソッドの引数に指定することも可能です。
他にもメソッドの戻り値、クラスのフィールドやプロパティにも利用することができます。


namespace Sample
{
  internal class Program
  {
    internal class Data
    {
      public string Field;

      public string Property { get; set; }

      public void Method()
      {
        Console.WriteLine($"Field={this.Field}, Property={this.Property}");
      }
    }

    static void Main(string[] args)
    {
      var data = new Data();

      data.Field = "field";
      data.Property = "property";

      Display(data);
    }

    // dynamic型を引数にするメソッド
    internal static void Display(dynamic d)
    {
      d.Method();
    }
  }
}

あとがき

匿名型は一時的な型とかLINQで普通に使います。と言うかLINQで使うのが殆どです。
対して、dynamic型は余程のことがない限りは使いません。IntelliSenseも機能しないので辛いです。

管理人
管理人

型に超厳しいC#ですらdynamic型は完全スルー。使う場合はそれなりの覚悟で使ってください。

◆ C#に関する学習コンテンツ

この記事は参考になりましたか?

関連記事

コメント

この記事へのコメントはありません。