Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

C# 1.1からC# 3.0まで~言語仕様の進化

C# 1.1からLINQまで

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2007/08/06 14:00

C#の言語仕様と.NET Frameworkはバージョンが上がると共に着実に進化し、よりエレガントになっています。C# 1.1から2.0、そして3.0に至る進化の過程をたどってみましょう。

目次

はじめに

 コードネーム「Orcas」で知られる次期Visual Studioは、Visual Studio 2008と命名され、今年の末にリリースされることになったそうです。2000年あたりからじわじわと浸透してきたC#はVisual Studio 2008でさらにバージョンアップし、C# 3.0となります。「Orcas」のβリリースで新機能を試していらっしゃる方も少なくないでしょう。

 本稿では、C# 1.1から3.0までの言語仕様の進化の一例をたどり、言語の進化がコーディング・スタイルに及ぼす影響を考えます。

対象読者

 C#が大好きな方、およびよりエレガントなコードを志向する駆け出し(?)プログラマ。

C#、LINQ and Whatnot

 Microsoft社員がユーザーに向けて発信している MSDN blogに面白い記事を見つけました。

 Jomo Fisher氏のblogではC#にまつわるさまざまなトピックを解説してくれているのですが、その中の1つに以下のものがあります。

 2005年9月の記事であることからも決して最新情報ではありません。ですが、この記事は筆者にとって、とてもためになりました。C# 1.1で書かれた1つのコードがC#のバージョンが上がるにつれて次第に磨かれていく様が活き活きと描かれています。ぜひ原文を読んでもらいたいのですが、英語が苦手な方のために、その概要を紹介します。

金時計をもらえる人は……?

 ここに従業員の情報を集めたクラスEmployeeがあります。

class Employee
// 従業員
class Employee {
  public string Name; // 名前
  public int Years; // 勤続年数
  public string Department; // 部署
}

 さて、会社は勤続年数が3年を超える社員に記念の金時計を贈ることにしました。そこでこのEmployee配列の中から金時計をもらえる社員をリストアップしなければなりません。

C# 1.1では……

 C# 1.1ならこんなコードで実現することでしょう。

C# 1.1
// 金時計をもらえる社員のリストアップ
static Employee[] GoldWatch(Employee[] employees) {
  // 条件を満たす社員数を求める
  int resultCount = 0;
  for ( int i = 0; i < employees.Length; ++i ) {
    if ( employees[i].Years > 3 ) {
      ++resultCount;
    }
  }
  // 必要なサイズの配列を用意する
  Employee[] results = new Employee[resultCount];
  // 条件を満たす社員を配列にコピー
  for ( int i = 0, j = 0; i < employees.Length; ++i ) {
    if ( employees[i].Years > 3 ) {
      results[j] = employees[i];
      ++j;
    }
  }
  return results;
}

 メソッドGoldWatchでは、まず条件を満たす要素の数を求め、必要なサイズの配列を確保し、そしてその配列の中身を埋めています。

 確かにこれでも動作しますがエレガントとは言い難いです。employeesは2度もスキャンされていますし、条件判断Years>3も2度評価されています。こんな「条件を満たす要素からなる部分集合を作る」という簡単な処理にしては、いささかややこしいコードです。

 より簡単に実装した例は、以下のようになります。

static Employee[] GoldWatch(Employee[] employees) {
  // 可変長配列を用意し、
  ArrayList results = new ArrayList();
  // 条件を満たす要素を追加する
  for (int i = 0; i < employees.Length; ++i) {
    if (employees[i].Years > 3) {
      results.Add(employees[i]);
    }
  }
  // 配列を取り出す
  return (Employee[])results.ToArray(typeof(Employee));
}

 .NET Frameworkライブラリが提供する可変長配列ArrayListを使うことで要素数を求めなくてもよくなりました。その一方で型に対する安全性が犠牲になっています。可変長配列ArrayListobjectを要素とするためです。そのため最後に複雑なキャストを行っています。

 これら2つのアプローチはいずれも柔軟性に欠けています。引数employeesは配列でなければなりません。ArrayListを引数とする同様のメソッドを追加することはできますが、さらにまた別の型をサポートしたくなるかもしれません。これでは、きりがありませんね。

 そこでまた別のアプローチが考えられます。

static Employee[] GoldWatch(IEnumerable employees) {
  // 可変長配列を用意し、
  ArrayList results = new ArrayList();
  // 条件を満たす要素を追加する
  foreach ( Employee employee in employees ) {
    if ( employee.Years > 3 ) {
      results.Add(employee);
    }
  }
  // 配列を取り出す
  return (Employee[])results.ToArray(typeof(Employee));
}

 このコードはEmployeeの配列のみならずArrayListのようなコレクションも引数として与えることができます。ただし型に対しては安全性が犠牲になってます。引数に与えられたIEnumerableが列挙してくれるのがはたして本当にEmployeeであるか、コンパイル時には判断できないためです。

 C# 1.1でできるのはここまででしょう。


  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • επιστημη(エピステーメー)

    C++に首まで浸かったプログラマ。 Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"り わんくま同盟でたまにセッションスピーカやったり 中国茶淹れてにわか茶人を気取ってたり、 あと Facebook とか。 著書: - STL標準...

All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5