連載:C# 4入門

第5回 Office連携でrefキーワード不要

株式会社ピーデー 川俣 晶
2010/11/19
Page1 Page2 Page3

Wordの悪夢

 破滅的に冗長なコードというものがある。もちろん、回避できればそれに越したことはない。しかし、いかにコードの効率アップを目指しても仕様的に回避できない冗長さもある。

 例えば、ただ単にMicrosoft Wordで指定された文書を開くというだけの事例を見てみよう。このようなコードは、Visual StudioにOffice連携の機能が含まれる以上、簡単に書ける……はずである。

 しかし実態はかなり驚愕(きょうがく)すべきものであった。

 3.0までのC#の仕様範囲内で書いた例を最初に紹介しよう。ちなみに、まず「Microsoft.Office.Interop.Word」への参照を追加しておく必要がある。

using System;
using Microsoft.Office.Interop.Word;

class Program
{
  static void Main()
  {
    object filename = "sample.docx";
    object missing = System.Reflection.Missing.Value;

    var app = new Microsoft.Office.Interop.Word.Application();
    app.Visible = true;
    app.Documents.Open(ref filename,
      ref missing,
      ref missing,
      ref missing,
      ref missing,
      ref missing,
      ref missing,
      ref missing,
      ref missing,
      ref missing,
      ref missing,
      ref missing,
      ref missing,
      ref missing,
      ref missing,
      ref missing);
  }
}
リスト1

 具体的な問題点は以下のとおり。

  • 不必要な「refキーワード」が多すぎる。渡すだけで戻す必要は何もない
  • 変数missingが多すぎる。省略したい引数なのに、書かなくてはいけない
  • 変数filenameはstring型と分かっているのに、object型にしなければならない(参照で渡す定義がobject型だから)
  • 変数missingは単に省略されていることを参照渡しで示すためだけに用意されたもので、何ら特別な意図を表現していない

なぜこんなことに?

 以下の話はうろ覚えの要素を多く含むので、間違いがあればご指摘いただきたい。ちなみに、検証したくても、すぐVisual Basic 4.0が動く環境の持ち合わせがないのである(さすがに古すぎて、そのような環境は維持していない)。

 さて、このソース・コードはあまりに過大だ。単にファイルを開くという意図を示すにしてはあまりにも大きすぎる。しかも開くファイル名を指定する引数まで参照渡しにする必要など何もない。わざわざrefを付ける意味などありはしないのだ。

 なぜこういう仕様になっているのだろうか?

 その理由を考えることは重要だ。本当に面倒くさいだけなら、そのソフトが支持されているはずがないからだ。支持されているとすれば、そこには何かの理由があるはずだからだ。

 それ故に、以下のような解釈で思考停止するのはやめよう。

  • 開発者の頭が悪いから。マイクロソフトの社員はバカに決まっている

 また以下のような解釈もやめよう。

  • 支持なんてされていない。最新バージョンのOfficeを買いに行かない人がいくらでもいる

 この問題はOfficeのバージョンを問わず発生するのである。最新版を買う買わないの問題ではない。旧バージョンを使い続けるユーザーにも関係してくる話である。ということは、何か理由があってしかるべきである。それは何だろうか?

 それを考えるには、このような仕様が生まれた時代(恐らく1990年代前半)にさかのぼらなければならない。すでに、「その当時はまだ生まれていなかった」という読者もいると思うが、生まれていないことは考えることができない理由にはならない。例えば、筆者は世田谷線の七間町駅について考えることができるが、生まれる前に消えてなくなった駅なのだ。知識欲さえあれば、古い話をいくらでも受け入れることができる。

 では話を続けよう。

 COM(Component Object Model)が誕生した時代の状況はよく覚えている。

 COM誕生前夜、最も人気のあるプログラミング言語はVisual Basicであった。C#はおろかJavaも生まれる前の話である。本屋には山のようにVisual Basicの本が並んでいた。恐らく、現在のiPhone/iPad本にも負けないぐらいの数があり、しかも売れていた。C#の前身とされるDelphiはあったが、ボーランドの製品であり、マイクロソフト製品ではなかった。Delphiにもかなりの人気はあったが、マイクロソフト製品という意味ではダントツにVisual Basicが人気であった。

 そのVisual Basicで人気が高かった機能の1つが、VBXコントロールを後からインストールすることで拡張可能という仕掛けであった。このVBXコントロールの直接の後継技術が、当初「OCXコントロール」と呼ばれたActiveXコントロールということになる。それを裏で支える基本技術がCOMというわけである。

 従って、COMはVisual Basic連携をメインに据えて発展することが前提となる。では、この当時のVisual Basicとはどういう言語なのだろうか。実は、いまVisual Studio 2010などで使用できるVisual Basicとは細部がかなり異なっていた。

  • Variant型というどのような値でも格納できる特別な型が多用された(型のない動的なプログラミング)
  • メソッドへの引数はByValキーワードで値渡し、ByRefキーワードで参照渡しであったが、省略時のデフォルトは参照渡しであった
  • 引数の省略ができた
  • 参照渡しの引数に定数をそのまま渡すことができた

 つまり、Office製品との連携時の前述の問題点がすべて問題ではなかったのだ。

  • 不必要な「refキーワード」が多すぎる → 省略できた
  • 変数missingが多すぎる → 省略できた
  • 変数filenameはstring型と分かっているのに、object型にしなければならない → Variant型で受け渡すなら型名の違いはどうでもよい
  • 変数missingは単に省略されていることを参照渡しで示すためだけに用意されたもので、何ら特別な意図を表現していない → 参照渡しのために変数の用意は必要ない。定数を直接渡せる

 しかし、問題はその後である。生まれた当時に問題がなくても、いまを生きるわれわれに問題はある。

 ここでこう思った読者も多いと思う。

  • 適切な仕様変更をすべきである

 しかし、これはNGである。過去に積み上げてきた資産を持たず、失うものもほとんどない開発者は、すぐに新しいものに飛びつける。だが、社会の多くの人や組織は、継承すべき資産を持っている。特に開発を始めたばかりの人は「XXを使えば簡単なのに」と思いがちだが、それはニーズの半分しか見ていないことになる。しかも、よく目にするネットの世界は歴史が浅く、資産の蓄積がほとんどない状態でスタートしているから、なおさらネット上には「資産の継承」という価値観が乏しい。

 だが、実際はこの仕様通りに呼び出しているツールが山のようにすでに存在し、使われているのである。もし、仕様変更したらそれが動かなくなる。バージョンアップでも動かなくなるリスクがあるが、仕様変更すれば確実に動かなくなる。動かないリスクはできるだけ避けたい。修正すれば金が掛かるからである。オープンソース信者は「誰かが……」といいたがるが、こういう創造性も何もない単なる仕様合わせの書き換えを喜んで行うボランティアはほとんどいない。全然面白くもないし、褒めてももらえないからである。誰がやっても、できて当たり前である。実行するモチベーションに乏しいし、まして、どこの誰かも分からない相手がいじったソース・コードなど怖くて使わないという開発者も珍しくないだろう。

 しかも、品質を保証するには1文字でも書き換えたらテストを最初からやり直しだ。関係ないと思った部分に影響が波及する例もあるから、テストは手が抜けないが、そういう単純作業の繰り返しを喜んでやってくれる人はほとんどいないし、仕事として実行させると金と時間がかなり掛かる。業務のノウハウが入っていたら、そもそもソース・コードを見せたくないと思うかもしれない。

 それ故、リスクを減らすために互換性は維持されねばならない。どれほど間違った仕様であろうとも、使用されてしまったらそれはいつまでも維持されねばならない。たとえ間違ったつづりでAPIを公開してしまったとしても、それは訂正できない。こういう問題は回避できないことが多い。

 そのあたりの事情を理解していないと、「世の中は間違っている」と思い、正義の義憤に駆られて世直しをしたくなるだろうが、実際には是正される悪などめったにあるものではない。良くない仕様は、指摘されるまでもなく、たいてい開発者は分かっているのである。しかし、修正ができないのである。

 だから、Microsoft Officeもそう簡単に仕様変更はできないわけだ。

 一方で、C#はより新しい世代の技術であり、しかも変化を厭(いと)わない。もちろん資産の継承性は重視しているのだが、それはC# 1.0以降の話であり、それ以前の資産をスムーズに継承できるかは二の次、三の次として扱われてきた。

 そこで起こるのが技術の世代差によるかみ合わない状況、いわゆる「インピーダンス・ミスマッチ」(=両者の構造や仕様が合致しないこと)である。2つの技術がどちらも効率を重視して仕様を決めているのに、インピーダンス・ミスマッチがあるため、2つを連携させると効率が落ちてしまうのである。

 では、この問題は解決できないのだろうか?

 そうではない。C#はこの問題をようやく解決したのである。二の次にも、三の次にも解決されたかった問題であるが、四の次つまりC# 4での解決を拒絶したわけではなかったのだ。

 

 INDEX
  C# 4入門
  第5回 Office連携でrefキーワード不要
  1.Wordの悪夢/なぜこんなことに?
    2.refキーワードの省略と引数の省略/dynamic型の価値/名前付きの引数
    3.良いOfficeと悪いOffice/まとめ
 
インデックス・ページヘ  「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 記事ランキング

本日 月間