アセンブリを動的に参照したい

 N/P Twinsの開発も進んできたのですがそろそろSDLでは描画性能が不足してきました。
 Core2Duo 2GHzくらいあれば余裕ですが、2D縦シューでそこまで要求するのはいかがなものかと・・・
 SDLはマルチプラットホームが魅力なので、C#+SDLを基本とするとして、Windows版についてはDirectXも併用して描画性能を上げようと考えています。



DirectXアセンブリを参照設定すると他環境で起動しなくなっちゃう?


 C#(.Net)から、DirectXを使うとなるとManaged DirectX(以下MDX)を使うのが一般的かと思います。
 しかしプロジェクトに参照設定でMDXを追加していると、MonoなどMDXをサポートしていない環境で起動できなくなってしまいます。


【コード例】


Microsoft.DirectX.Vector2 vec;
vec = new Microsoft.DirectX.Vector2(1.0f, 2.0f);


【実行結果例】


$ mono ConsoleApplication1.exe

** (ConsoleApplication1.exe:19398): WARNING **: The following assembly referenced from /home/fukaya/work/monotest/ConsoleApplication1.exe could not be loaded:
Assembly: Microsoft.DirectX (assemblyref_index=2)
Version: 1.0.2902.0
Public Key: 31bf3856ad364e35
The assembly was not found in the Global Assembly Cache, a path listed in the MONO_PATH environment variable, or in the location of the executing assembly (/home/fukaya/work/monotest/).
※ 以下省略

 起動時にWARNINGがでて全く実行できません。




次の場合はWARNINGは発生せず、起動してMDXに関係のない行は実行できました。
a) MDXを参照設定しておくだけ
b) 変数宣言だけした場合
 Microsoft.DirectX.Vector2 vec;
c) 到達しない場所でインスタンスを生成する場合
 if ( false ) vec = new Microsoft.DirectX.Vector2(1.0f, 2.0f);


 以上は単にコンパイル時に削除されてるだけかもしれませんね・・・




 Windows以外の環境で実行時にはインスタンスを生成しないように条件分岐していてもやっぱり起動時にWARNIGが出ました。
【コード例】


if (System.Environment.OSVersion.Platform == PlatformID.Win32Windows)
{
vec = new Microsoft.DirectX.Vector2(1, 2);
}


 むう。
 起動時に一通りチェックされちゃうのかなあ。
 でてるのは、WARNINGなのでこれを無視できる設定あればいいのになあ。


● 動的にアセンブリを読み込む

 使うときだけ動的にアセンブリを読み込めば、まあOKですね。

【参考ページ】
Re[4]: 動的リンクの記述方法について


 このページを参考にしてDirectXのVector2クラスのインスタンスを生成して、ToString()メソッドを呼んでみました。

【コード例】


System.Reflection.Assembly classLibrary1 = System.Reflection.Assembly.LoadFile(@"C:\WINNT\Microsoft.NET\DirectX for Managed Code\1.0.2902.0\Microsoft.DirectX.dll");
Type class1 = classLibrary1.GetType("Microsoft.DirectX.Vector2");
object instance = class1.InvokeMember(null, System.Reflection.BindingFlags.CreateInstance, null, null, null);
string result = (string)class1.InvokeMember("ToString", System.Reflection.BindingFlags.InvokeMethod, null, instance, null);


 うまくいきました。
 でもこれは面倒くさいよ・・・
 MDX関係をもっと抽象度の高いクラスでラップしてやればI/Fを最小化できるかなあ。



● あれ?別メソッドに移したらうまくいったよ?

 いままで、テストコードは全部Mainメソッドに書いていました。
 が、思い立ってメソッドにしたら・・・WARNINGが出なくなりました!


 どうやら実行するメソッドの開始時にチェックしているようです。
 当然、分けたメソッドの方を呼び出すと、その時点でWARNINGがでてプログラムは終了します。


 この方法で、OSに対するポータビリティを確保したままDirectX対応も出来そうです。
 安心してキャラいっぱい出せます。



※ しかしこれでよいものか。他によい方法があったらアドバイスくださいませ。
※ 使用環境;CentOS 5.2 + Mono JIT compiler version 1.9.1
※ マルチプラットホームと言う意味では、SDL+OpenGLとして、スプライトはテクスチャを貼ったポリゴンでもよかったかもしれず
※ 「SDL DirectX8」で検索するとSDL 2.0の話題が・・・。2002/9/4のエントリ・・・