連載:C# 3.0入門

最終回 LINQ to SQL/落ち穂拾い

株式会社ピーデー 川俣 晶
2008/12/05
Page1 Page2 Page3

落ち穂拾い

 これまでの連載で触れることがなかった2つの話題について補足して連載を終わることにしよう。

■部分メソッド定義

 部分メソッド定義(partial method)は、確かにC# 3.0の新機能であるのだが、C# 3.0関連資料から漏れていることも多く、見落とされがちな機能といえる。また、単なる筆者の見落としかもしれないが、有効活用されている事例も見た記憶がない。

 さて、部分メソッド定義とは部分クラス定義(partial class)とともに使用する機能で、部分クラス定義が複数あるとき、その中の1つでメソッドの名前と引数だけを定義し、実体は別の部分クラス定義に記述する機能である。

 具体的な内容はサンプル・コードを見る方が分かりやすいだろう。

using System;

partial class A
{
  partial void sample()
  {
    Console.WriteLine("Sample called");
  }
}

partial class A
{
  partial void sample();

  public void CallSample()
  {
    sample();
  }
}

class Program
{
  static void Main(string[] args)
  {
    var a = new A();
    a.CallSample();
    // 出力:Sample called
  }
}
リスト2 部分メソッド定義の記述例

 もちろん、実際に使用する場合は個々の「partial class A」の定義は別ファイル上にあって分離されていることが多いだろう。

 さて、部分メソッド定義は「partial void sample();」のようにpartialキーワードを付けて指定する。このメソッドは2つ目のpartial class Aで宣言されているが、実装本体は1つ目のpartial class Aにある。

 この機能のポイントは「実装がないときはエラーも出さずに呼び出しごと消えてなくなる」ことにある。そう、実体がなくなるだけではなく、実体への呼び出しごと消えてなくなるのである。

 具体的に見るために、.NET Reflector(ILDSAMでもOK)でCallSampleメソッドを逆アセンブルしてみよう。

.method public hidebysig instance void CallSample() cil managed
{
  .maxstack 8
  L_0000: nop
  L_0001: ldarg.0
  L_0002: call instance void A::sample()
  L_0007: nop
  L_0008: ret
}

 確かに、sampleメソッドをcallするILの命令が含まれている。では以下のように、1つ目のsampleメソッドをコメントアウトして同じことを試してみよう。

//partial void sample()
//{
//  Console.WriteLine("Sample called");
//}

 すると以下のようになる。

.method public hidebysig instance void CallSample() cil managed
{
  .maxstack 8
  L_0000: nop
  L_0001: ret
}

 見てのとおり、sampleメソッドをcallするILの命令は消えてなくなった。

 このような機能性から、部分メソッド定義は拡張可能な部分クラスに利用できることが分かる。例えば、実行中に発生するさまざまな出来事を、部分メソッドの呼び出しで伝達するように部分クラスを記述できる。このようなイベントは、別の部分クラスに部分メソッドの実体を定義することで受け取って処理できる。

 この仕掛けは、C#自体が持つEventを使えば同等の機能が記述できるように思えるかもしれない。だが、部分メソッド定義を使って実現した場合、1つだけ決定的な長所がある。それは、処理する実体がないイベントは、イベントの呼び出しコードそのものが消滅することである。それにより、従来のEventよりも、よりコンパクトで効率のよいコードが生成可能となる。

 しかし、Eventと違って部分メソッド定義は呼び出し先の確定作業をコンパイル時に行う必要があるため、自由度は低い。実行時に必要に応じてイベントハンドラを付けたり外したりはできないのである。さらに部分メソッド定義は以下のような制約を持つ。

  • void型を返す必要がある
  • outパラメータは使用できない
  • 暗黙的にprivateとなる。リスト2の「partial void sample();」は、privateとは明記していないがprivateとして扱われているので、外部から直接呼び出すことはできない
  • virtualにはできない(privateである以上、virtualにする意味もない)
  • externにはできない
  • 部分メソッドに対するデリゲートを作ることはできない

 ただし、以下のことは可能だ。

  • refパラメータは使用できる
  • static修飾子とunsafe修飾子は使用できる
  • ジェネリック・メソッドにできる(制約は部分メソッドの定義宣言に置き、必要に応じて実装宣言で繰り返すことができる。パラメータ名と型パラメータ名は、定義宣言と実装宣言で同じである必要はない)

 これらの制約を見て分かるとおり、制限は厳しい。恐らく、開発中のプログラムに後から部分メソッド定義の機能を当てはめてスピードアップを図るような使い方はうまくいかないことも多いだろう。設計段階から、部分メソッド定義が適用できるよう、配慮しないとなかなかうまく機能しないかもしれない。しかし、性能面が問題になる場合は使うと価値があるかもしれない。

■C# 3.0コンパイラ

 C# 3.0コンパイラにいくつかスイッチが追加されているので、簡単に紹介しておこう。

  • /win32Manifest

 実行可能ファイルに埋め込むユーザー定義のWin32アプリケーション・マニフェスト・ファイルを指定する。例えば、Windows Vistaで管理者権限を要するプログラムは、この機能で「requireAdministrator」の要求実行レベルを指定したカスタム・マニフェストを指定できる(Visual Studioで開発中は、プロジェクトのプロパティでも指定できる)。

  • /noWin32Manifest

 マニフェストの埋め込みを行わないことを指定する。これを使用すると、(別の経路で指定されない限り)Windows Vista上では仮想化されて実行されることを意味する(Visual Studioで開発中は、プロジェクトのプロパティでも指定できる)。

 これらは、C# 3.0のための機能というよりも、Windows Vistaのための機能といえる。しかし、これらの機能が具体的に何を実現するかは、もしかしたら直感的に分かりにくいかもしれない。というのは、そもそもUACに対する具体的な知識が驚くほど世の中に普及していないという感があるからだ。

 例えば、Vistaでは動かないソフトが多すぎるといった批判が「誰もが承認した常識的事実」として語られる機会は多いが、筆者の過去の経験からいえば、Vistaで動かないソフトは一般のアプリケーションに限ればほんの一握りでしかない。単に立ち上げるだけでは動かないソフトは珍しくもないが、それはUACによって動作がブロックされているだけの話であり、適切な権限で動作するように設定すればたいてい動作する。そして、安全なOSを求めるユーザーの大合唱に応えるために導入されたのがUACである以上、いまさらUAC抜きの世界には戻れない。

 それにもかかわらず、安全なOSをよこせと要求したユーザーたちが、自分たちの安全を実現するために用意されたUACの機能を理解できず、危険性の高いWindows XPをいつまでも使い続けようとする態度はよく見られる。これは、安全のための歩道橋を作れと要求しながら、いざ歩道橋ができると階段が面倒なので道路を直接突っ切るような態度と同様といえる。それは、決して賢い態度ではない。

 これらのコンパイラ・スイッチは、そのような意味で賢くあろうとする開発者のためのものだといえる。もはやUACのない世界に戻るという選択肢がほとんどあり得ない以上、このような機能をマスターして素晴らしいプログラムを世に送り出そう。

連載の終わりに

 C# 2.0入門連載の最後に以下のように書いた。

「C# 1.xが解放者、C# 2.0が予言者だったとすると、C# 3.0は何に当たるのだろうか。」

 C# 3.0は開拓者だというのが、現在の筆者の考えである。つまり、C# 2.0が指し示した「可能性」としての未来は、C# 3.0では「現実」に置き換えられる。

 C# 3.0が現実となり、期待どおりの手応えをC#プログラマーに対して提供している現在、C# 3.0は終着点ではないことがすでに示されている。現時点でVisual Studio 2010 CTPが提供され、C# 4.0の開発中バージョンがすでに利用可能となっている。

 では、C# 1.xが解放者、C# 2.0が予言者、C# 3.0が開拓者だとすると、C# 4.0は何になるのだろうか? 恐らく移住者ではないかと思う。移住者とは、開拓済みの新天地に移住してくる者たちを示す。

 C# 3.0は、新しい境地を切り開く機能がそろっているが故に、それを使う側にも開拓者スピリッツが要求されたという側面がある。それ故に、ハードルの高さを感じた技術者も多いのではないだろうか。しかし、C# 4.0の時代になれば、もはやそれは新しくはない。実績のある安定した機能でしかない。

 さらにいえば、移住者は開拓者と違って、さまざまなタイプの人たちが押し寄せることになる。そういった多様な相手の多様な要求に対応するためには、C#自体も偏りの少ない全方位的な機能性を獲得する必要がある。これまでずっと静的に型付けされた言語であったC#が、4.0になって動的な型付けを導入するのはそのような文脈で見ると分かりやすいだろう。

 もはやC#は、C#的な理想に賛同する人だけの言語ではなく、幅広い技術者層に対して広い間口を提供していかねばならないのである(ちなみに、比較的リフレクションを多用する筆者は、動的な型付けの導入でコードが簡素化できそうなので歓迎である)。

 しかし、4.0時代になっても、3.0時代の技術が消えるわけではない。いや、むしろ3.0的な使い方がよりスマートかつパワフルになるとすらいえる。例えば、LINQのクエリを複数のCPUコアに分散するパラレルLINQ(P-LINQ)などの新技術が提供され、3.0流のやり方もパワーアップしている。これは、たとえ間口を広げるとしても3.0流のやり方が間違っていなかったと判断されているためだろう。C# 4.0を目指すためであっても、C# 3.0にチャレンジしてマスターする価値は高いだろう。

 なお、前回の最後でアナウンスした「LINQ to XML」についての解説は、ページ数の都合で残念ながら割愛した。それ単体で意義のあるテーマであるため、これについては別途、独立した話題として提供できればよいと考えている。End of Article

 

 INDEX
  C# 3.0入門
  最終回 LINQ to SQL/落ち穂拾い
    1.SQL Serverのワナ/LINQ to SQLという突破口
    2.LINQ to SQLのサンプル/LINQ to SQLとメソッド構文/まとめ
  3.部分メソッド定義/C# 3.0コンパイラ/連載の終わりに
 
インデックス・ページヘ  「C# 3.0入門」


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 記事ランキング

本日 月間