連載:C# 4入門

第7回 DynamicObjectを継承したダイナミックなクラス

株式会社ピーデー 川俣 晶
2011/01/14
Page1 Page2 Page3

動的な演算子

 実は演算子も動的に処理できる。以下は「+演算子」に配列の要素ごとの加算の機能を与えたものだ。

using System;
using System.Dynamic;
using System.Linq.Expressions;

class IntArray : DynamicObject
{
  public int [] Value { get; set; }

  public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result)
  {
    if (binder.Operation != ExpressionType.Add)
    {
      result = null;
      return false;
    }

    result = new int[Value.Length];

    for (int i = 0; i < Value.Length; i++)
    {
      ((int[])result)[i] = Value[i] + ((IntArray)arg).Value[i];
    }
    return true;
  }
}

class Program
{
  static void Main(string[] args)
  {
    dynamic x = new IntArray();
    x.Value = new int[] { 1, 2, 3 };

    dynamic y = new IntArray();
    y.Value = new int[] { 4, 5, 6 };

    var z = x + y;

    foreach (var n in z) Console.WriteLine(n);
  }
}
リスト6

5
7
9
リスト6の実行結果

 これを実現するには、ダイナミック・オブジェクトのTryBinaryOperationメソッドをオーバーロードすればいいわけだが、この場合は名前が文字列で入ってくるわけではないので、binder.Operationプロパティの値がExpressionType列挙型のどれに当たるかを調べる。その結果、以下の式は単なる加算ではなく、Valueプロパティのint[]の要素ごとを足し合わせる機能を持つことになる。

var z = x + y;

 だから、{1,2,3}と{4,5,6}を足すと{5,7,9}という結果になるわけである。ただし、単なる演算子のオーバーロードを行う機能であれば、すでにC#に存在する。あくまで動的に扱えることがダイナミック・オブジェクトならではの特徴である。

まとめ

 今回のまとめ。

  • ダイナミック・オブジェクトは動的な扱いに関しては最強の道具である
  • あらゆる名前の存在しないメンバ、プロパティ、メソッドを自由に処理できる
  • 処理する際に名前を参照できる
  • うまくハマるとコードが大幅に簡素化される
  • しかし、乱用はお勧めしない。なくて済むなら使わない方がいい

 実は以前から考えていたことがある。ダイナミック・オブジェクトには、あまり出番がない。というよりも、少なくとも筆者は実際に稼働するソース・コードで使ったことが一度もない。すでにVisual Studio 2010とC# 4が手放せないぐらい使い込んでいるが、この機能は使ったことがない。ある意味で、なくてもよい機能であるような印象さえ受ける。

 では、ダイナミック・オブジェクトの出番は本当にないのだろうか。

 実は、「ない」ともいいきれない。これが便利である若干の事例のほかに、実は重要な使い道があることに気付いた。動的言語のソース・コードを1対1で素直にC#のソース・コードに置き換えることができるのだ。

 一見、無駄に思えるこの書き換えだが、ある前提を導入すると無理でも無意味でもなくなる。それが「中間言語としてのC#」である。

 最近では知っている人も少ない話なのだが、実は初期のC++コンパイラはC言語へのトランスレータとして実装されていた。つまり、C言語を中間言語として使うという発想である。C言語へ変換してしまえば、実績あるC言語コンパイラでいくらでも効率のよい実行ファイルを作成できた。そこまでC++コンパイラが抱え込むよりも効率的である。

 同じようなことが、いまどきのコンパイラでもいえる。.NET Framework上で動くプログラミング言語を実装する際、低水準のIL(中間言語)コードを直接吐き出すコードを書くこともできるが、低水準ゆえに手間が多くかかる。コンパイラが行うべき最適化もすべてやらねばならない。一方で、C#はC#のソース・コードを動的にコンパイルして実行することも容易だ。そこで、C#のソース・コードを動的に生成してコンパイルさせることができる。それで、動作は効率が上がり、プログラムも簡単になる。

 つまり、直接使うというよりも、動的言語のコンパイラが作りやすくなったと見るべきものだろう。そもそも多くの動的言語のソース・コードは、型付けが弱く、ソース・コード上に型情報がないのだから、型に依存しない動的なコードを簡潔に記述できる機能は十分に役立つだろう。

 一方で、強い型付けされた言語に慣れたプログラマーからは、無意識的に回避されてしまう利用形態であるともいえる。それ故に、使い方にはかなり偏りがありそうである。しかし、決して無意味ではあるまいと思う。End of Article

 

 INDEX
  C# 4入門
  第7回 DynamicObjectを継承したダイナミックなクラス
    1.クラウド・クラウド・クラウド/状態を保管する/状態を保管する
    2.ダイナミックに解決せよ!/この機能は便利か?/動的なメソッド
  3.動的な演算子/まとめ
 
インデックス・ページヘ  「C# 4入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間