|
|
連載:[完全版]究極のC#プログラミング
Chapter10 名前空間のエイリアス修飾子と外部アセンブリ
川俣 晶
2009/12/14 |
|
|
10.3 アセンブリ間の名前競合の解決
ここまで見てきた機能は、紛らわしい名前を的確に区別する手段といえる。実際には同じではない名前をうまく区別できない問題を解決する。
しかし、最初から同じ名前が衝突するケースもある。もちろん、通常の開発時にはありえない事態である。名前が衝突したらコンパイルが通らないので、たいていはどちらかの名前を変更して回避する。だが、複数の既存のアセンブリを参照して開発を行う場合には修正できない名前の衝突が起こる可能性がある。たとえば、別個の組織から提供される別個のアセンブリが、たまたま同じ名前のクラスなどを定義してしまうことはありうるだろう。参照したアセンブリ間の名前の衝突は、それらのアセンブリがバイナリーファイルで提供されているとすれば、容易に解決することはできない。
この問題に対処するために用意されたのが「externエイリアス」という機能である。
まず、上記の理由により名前が衝突するケースを見てみよう。
Visual Studio 2005で、コンソールアプリケーション1つとクラスライブラリ2つのプロジェクトを含むソリューションを作成する。コンソールアプリケーションからは、その2つのクラスライブラリのプロジェクトを参照しておく。
図10.1のような感じである。
個々のソースコードは、以下のリスト10.4、リスト10.5、リスト10.6のような内容になっている。
|
図10.1作成したソリューションの構成 |
Visual Studio 2008で、1つのコンソールアプリケーションプロジェクトと2つのクラスライブラリプロジェクトを含むソリューションを作成する。 |
using System;
namespace ClassLibrary
{
public class Class
{
public static void SayHello()
{
Console.WriteLine("Hello in ClassLibrary1!");
}
}
}
|
|
リスト10.4 ClassLibrary1.Class1.cs |
using System;
namespace ClassLibrary
{
public class Class
{
public static void SayHello()
{
Console.WriteLine("Hello in ClassLibrary2!");
}
}
}
|
|
リスト10.5 ClassLibrary2.Class1.cs |
using System;
class Program
{
static void Main(string[] args)
{
ClassLibrary.Class.SayHello();
}
}
|
|
リスト10.6 ConsoleApplication82.Program.cs |
ソリューションをビルドすると次のようなコンパイルエラーが出る。
エラー 1 型 'ClassLibrary.Class' は '……\ClassLibrary1.dll' および '……\ ClassLibrary2.dll の両方に存在します。
|
|
ソリューション(リスト10.4、5、6)のコンパイル結果 |
この名前の衝突を、2つのクラスライブラリを修正することなく解決するには、次の3つの手順を必要とする。
参照にエイリアス名を設定する
externエイリアスの定義を追加する
externエイリアスを用いてメソッドを呼び出す
まず、参照にエイリアス名を設定するには、ソリューションエクスプローラから参照しているアセンブリのプロパティを開く。図10.1の画面例では、[ConsoleApplication82]−[参照設定]の下の「ClassLibrary1」を右クリックし、メニューから[プロパティ]を選ぶ(図10.2参照)。
|
図10.2ClassLibrary1の参照プロパティ |
コンソールアプリケーションで参照設定している「ClassLibrary1」を右クリックし、メニューから[プロパティ]を選んで表示する。 |
ここで、[エイリアス]に「global」という名前が入っているが、これをアセンブリを参照するための別の名前に書き換える。参照するアセンブリごとに異なる名前を書き込んでおく。ここでは、「Lib1」という名前を指定しておこう。同様にして、ClassLibrary2については「Lib2」という名前を指定した。
次に、externエイリアスの定義の追加である。これはソースコードの先頭にリスト10.7の2行を追加する。
extern alias Lib1;
extern alias Lib2;
|
|
リスト10.7 リスト10.6の先頭に追加するexternエイリアスの定義 |
内容は簡単である。「extern alias」の後に、参照プロパティに書き込んだ名前を書くだけである。これで、ソースコード内でこの名前を参照する準備ができた。
後は、externエイリアスを用いてメソッドを呼び出すだけである。
// リスト10.6のコード
ClassLibrary.Class.SayHello();
|
|
// externエイリアスを用いた呼び出し
Lib1.ClassLibrary.Class.SayHello(); // 出力:Hello in ClassLibrary1!
Lib2.ClassLibrary.Class.SayHello(); // 出力:Hello in ClassLibrary2!
|
|
externエイリアスを用いてメソッドを呼び出す |
または
// externエイリアスを用いた呼び出し(「::」を使用)
Lib1::ClassLibrary.Class.SayHello();
// 出力:Hello in ClassLibrary1!
Lib2::ClassLibrary.Class.SayHello();
// 出力:Hello in ClassLibrary2!
|
|
externエイリアスを用いてメソッドを呼び出す |
externエイリアスの後は「.」でもよいが、名前空間エイリアス修飾子(::)のほうが名前衝突のリスクが少ないので好ましいだろう。
このように、アセンブリに付加したエイリアス名を含む名前を使ってアクセスすることで、まったく同じ名前が別個のアセンブリに含まれている場合でも、それらを区別して扱うことができる。
【Exercise】練習問題
グローバル名前空間や名前空間エイリアス修飾子を使用しなければならない理由は何か? 正しいものを選べ。
- 名前空間を拡張するため
- 名前空間の別名を定義するため
- たまたま同じ名前が競合すると意図しないものが選ばれてしまうことがあるため
- 国際化(Globalization)を実現するため
- 異なるアセンブリを参照するため
◎解答:「3」(この行をマウスで選択してください)