連載:C# 4入門

第6回 in/outキーワードと共変性と反変性

株式会社ピーデー 川俣 晶
2010/12/17
Page1 Page2 Page3

 先日、米国でPDC10が開催され、C#の未来に関しても発表が行われた。また、Visual Studioの次バージョンのCTPも公開され、まだ進化が続くことが示された。ちなみに、同時通訳付きの中継も行われた。日本時間では深夜開催となるので、基調講演だけ聴いてその後は耐えられず寝てしまったが、よい時代になったものである。

 さて、気になったことは2つある。

  • 影響度の割に認知度が低い
  • もうラムダ式は説明なしに使われている

 1つ目は、このイベントについて言及している人が身近に1人しかいなかったことだ。マイクロソフトのPDCといえば技術的な意味で時代の区切りとなるイベントであり、影響力は絶大だ。実際、マイクロソフトの技術で仕事をしている人に限られず、ライバル技術で仕事をしている人にも関係する話だ。好意的に見ていても、そうではないとしても、ここで発表された技術に活動が影響されることは避けられない。どこまでマイクロソフトの技術を避けていても、ライバル製品である以上はそれを意識した機能性を持たざるを得ないからである。

 ところが、そういうインパクトのあるイベントであるにも関わらず、それにインパクトがあるという認識は低いように思える。ネイティブの英語はどうせ聴いても分からないというあきらめならともかく、今回のPDCでは日本語同時通訳付きである。そうまでして時代をなめてかかると、後で痛い目を見るのは自分たちかもしれないと思うが、まあそれは横に置こう。情報の感度が低すぎることで受けてしまう不利益、ペナルティは、この連載のテーマではない。

 2つめの話題である。未来のC#のテーマは「非同期処理」であることが示されているが、それを実現するサンプル・コードにラムダ式が当たり前のように出てくるのである。その結果として、Visual Studio 2005を使い続けるプログラマーは、ステップアップしようとしてもサンプル・コードが読めないことを意味する。新機能は丁寧に説明されていても、いまさらラムダ式の説明はないからだ。

 これは以前から危惧(きぐ)しているとおりだ。そもそも、変化が激しいC#にスキップしてよいバージョンはないが、Visual Studio 2008(C# 3.5)は特にスキップしてはいけない重要なバージョンだった。だが実際は多くの人がスキップしてしまったらしいうえ、「2005と似ているからスキップしてよい」と誤認した人も多いようだ。このような問題でトラブルが多発したり、分からないから新しいバージョンにいつまでも移行しない(できない)問題が生じたりする可能性もある。しかし、それも本題ではないので、横に置こう。

 ちなみに、Visual Studioの新バージョンは「Visual Studio Async」という名前らしい。年度を名称に入れるのは恐らく2002以降のVisual Studioだが、それも2010で終わることになる。しかし、この話題も横に置こう。なぜなら、われわれには十分に2010もまだ、認知度不十分の新バージョンだからだ。今回も、C# 4の新機能を見ていくことにしよう。

用語について

 以下の用語は頭の片隅に入れておくとエラー・メッセージなどが分かりやすくなるかもしれない。簡単にまとめておこう。

  • 共変 : 型パラメータがoutの場合
  • 反変 : 型パラメータがinの場合
  • 不変 : outでもinでもない場合

ジェネリック使用時の制約

 以下のようなプログラムをVisual Studio 2008で作成したとしよう。これは問題なくコンパイル可能であり、動作する。

using System;
using System.Collections.Generic;

class Program
{
  static void 汎用列挙出力(object[] e)
  {
    foreach (var n in e) Console.WriteLine(n);
  }

  static void 文字列列挙専用(string[] e)
  {
    汎用列挙出力(e);
  }

  static void Main(string[] args)
  {
    文字列列挙専用(new[] { "hop", "step", "jump" });
  }
}
リスト1

hop
step
jump
リスト1の実行結果

 string型の配列は、object型の配列に変換可能であり、それによって特に大きな問題は起きない。列挙して出力しても問題はない。

 しかし、ここで1つの疑問を感じたとしよう。

 「いまのままでは、配列しか受け渡せないが、引数を配列から列挙インターフェイスにすれば、列挙インターフェイスを持つすべてのコレクションを列挙できるぞ。」

 そこで、このアイデアどおりにソース・コードを改造したのは以下の例である。

using System;
using System.Collections.Generic;

class Program
{
  static void 汎用列挙出力(IEnumerable<object> e)
  {
    foreach (var n in e) Console.WriteLine(n);
  }

  static void 文字列列挙専用(IEnumerable<string> e)
  {
    汎用列挙出力(e);
  }

  static void Main(string[] args)
  {
    文字列列挙専用(new[] { "hop", "step", "jump" });
  }
}
リスト2

 ところが、このソース・コードはVisual Studio 2008ではコンパイル・エラーでコンパイル不能になってしまうのである。IEnumerable<string>型からIEnumerable<object>型への変換ができないからである。しかし、これはあまり意味がある制約とはいえない。なぜなら、string型からobject型への変換は安全だからだ。配列なら変換できるが、ジェネリック・インターフェイスでは変換できないのは、単なるプログラミング言語の制約でしかない。

 だが、話はまだ終わらない。実は、このソース・コードはVisual Studio 2010に持ち込むとエラーにならず、コンパイル&実行可能になるのだ。そして、これはある程度の汎用的な機能を作り込もうと思うと、便利な特徴になる。

 では、なぜ2010では有効なのだろうか。

 2008と2010の定義の差を見てみよう。Visual Studioのエディタ上で「IEnumerable」を右クリックして[定義へ移動]を選ぶと簡単に比較できる。

public interface IEnumerable<T> : IEnumerable
Visual Studio 2008

public interface IEnumerable<out T> : IEnumerable
Visual Studio 2010

 ずばり、「out」というキーワードが増えていることが分かる。これが2010でコンパイルできる秘密である。実は、Visual Studio 2010(.NET Framework 4)には、以下の2つの特徴がある。

  • in/outという新しいキーワードがサポートされている(言語の変更)
  • IEnumerableインターフェイスなどにそれが適用されている(クラス・ライブラリの変更)

 つまり、この問題は「言語の改良」ではあるが、同時にクラス・ライブラリも更新された.NET Framework 4対応のC# 4だから実現できたことなのである。

 以下で詳しく見てみよう。

 

 INDEX
  C# 4入門
  第6回 in/outキーワードと共変性と反変性
  1.ジェネリック使用時の制約
    2.実は単純ではないジェネリック/in/outキーワードの使いどころ
    3.両方同時に使えるか?/返却値ではない返却に注意/まとめ
 
インデックス・ページヘ  「C# 4入門」

@IT Special

- PR -

TechTargetジャパン

Insider.NET フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

イベントカレンダー

PickUpイベント

- PR -

アクセスランキング

もっと見る

ホワイトペーパーTechTargetジャパン

注目のテーマ

Insider.NET 記事ランキング

本日 月間
ソリューションFLASH