ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

C#コミュのクラスの動的な実装

  • mixiチェック
  • このエントリーをはてなブックマークに追加
C#で動的にクラスを実装する方法を探してます。どこかで「リフレクションを使う」
というのを見たのですが、「AssemblyBuilderクラスを使うらしい」というところまで
きたのですが、使い方がよくわかりません。
参考になるサイトなどご存知の方がいらっしゃいましたら、教えて下さい。

※VB6では、DLLをレジストリに登録しておき、CreateObjectを使用することで実現
 していた経験があります。
 

ちなみに構成なのですが、TESTL+"番号"というクラスをクラスライブラリで作成
しており、呼び出し元で入力された番号のクラスを使用するという想定です。
プログラムの構成上、インターフェースを使用しています。


■構成
インタフェース:TESTL
実装クラス  :TESTL01,TESTL02,TESTL03,・・・TESTLnn,

[TESTL]-[TESTLnn]
  1 :  n


■インターフェース
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace com.hoge.sample
{
public interface TESTL
{
// メール情報作成処理実行
Boolean exec();

// メール情報取得
ArrayList getItems();
}
}


■実装クラス
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace com.hoge.sample
{
public class TESTL01 : TESTL
{
#region TESTL メンバ

public Boolean exec()
{
throw new Exception("The method or operation is not implemented.");
}

public ArrayList getItems()
{
throw new Exception("The method or operation is not implemented.");
}

#endregion


public TESTL01() {
・・・
}
}
}


■実行プログラム
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;

namespace TestApplication
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
//
ArrayList al = new ArrayList();

// TESTL + (String)iのクラスを呼び出し


// メイン処理の実行
obj.exec();

// 処理結果の取得
al = obj.getItems();
}
}
}

よろしくお願い致します。

コメント(8)

CreateObject ってところから想像すると、
動的に実装するんじゃなくて、動的にロードするんですね。

やっぱり、リフレクション関連を調べます。
MSDN
http://msdn2.microsoft.com/ja-jp/library/system.reflection(vs.80).aspx

どぼんさんのところもわかりやすい
http://dobon.net/vb/dotnet/index.html
>よういちさん
回答ありがとうございます。
"どぼんさん"のところを参考にして実行ファイルを作ってみた
のですが、getTypeの結果がNullで返ってきてしまっていて、
その後が実行されませんでした。
GetTypeメソッドに与える引数は、namespace + クラス名だと
思っているのですが・・・。


■実行プログラム
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;

namespace TestApplication
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
Assembly asm = Assembly.LoadFile("C:\\sample\\bin\\TESTL01.dll");

Type t = asm.GetType("com.hoge.sample.TESTL01");

//Form1のインスタンスを作成する
object frm = t.InvokeMember(null,
System.Reflection.BindingFlags.CreateInstance,
null, null,
null);

//Form1のShowDialogメソッドを呼び出し、フォームを表示する
object result = t.InvokeMember("exec",
System.Reflection.BindingFlags.InvokeMethod,
null, frm,
null);
}
}
}
GetTypeじゃなくGetTypesの中身を覗いては如何でしょう?
// 呼び出される側のインターフェース
namespace Foo
{
public interface IBar
{
string SayHello(string yourName);
}
}

// インターフェースの実装(1)
// English.dll に実装することとする
namespace English
{
public class EnglishBar
: Foo.IBar
{
#region IBar メンバ

public string SayHello(string yourName)
{
return string.Format("Hello {0}!", yourName);
}

#endregion
}
}

// インターフェースの実装(2)
// Japanese.dll に実装することとする
namespace Japanese
{
public class JapaneseBar
: Foo.IBar
{
#region IBar メンバ

public string SayHello(string yourName)
{
return string.Format("{0}さん、こんにちは!", yourName);
}

#endregion
}
}

// クラスの動的呼び出し用ユーティリティ
using System;
using System.Configuration;
using System.Reflection;

namespace Utility
{
public class ClassLoader
{
public static object CreateInstance(Type type)
{
string setting = ConfigurationSettings.AppSettings[type.FullName];
if(setting == null)
return null;

string[] tokens = setting.Split(',');
if(tokens.Length != 2)
return null;

string typeName = tokens[0].Trim();
string assemblyString = tokens[1].Trim();

object instance;
try
{
instance = Assembly.Load(assemblyString).CreateInstance(typeName);
}
catch
{
instance = null;
}

return instance;
}
}

呼び出し側アプリケーションのApp.Settings の内容
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="Foo.IBar" value="English.EnglishBar, English" />
</appSettings>
</configuration>


// ユーティリティを使って実際に呼び出してみる
public class Invoker
{
public string Test()
{
Foo.IBar someone = ClassLoader.CreateInstance(typeof(Foo.IBar)) as Foo.IBar;
if(someone == null)
return null;

return someone.SayHello("MASHER");
}
}
}

// 結果
Hello MASHER!


おいらはこんな感じで使ってます。

App.Settings上でインターフェースとそれを実装するクラスを紐付けておき、実行時にはAppSettingsの内容を書き換えるだけで再コンパイル無しに挙動を変える、という感じです。

keyに、インターフェースのFullNameを、Valueに実装クラスのFullNameとそれが含まれるアセンブリ名をカンマ区切りで指定しておけばよい、ということで。

上の例で言えば、AppSettingsファイル内のvalue属性の値を
"Japanese.JapaneseBar, Japanese"
とすれば、

こんにちは、MASHER!

と出力されるはずです。


お試しあれ。
InvoleMemberメソッドは使わない方向で考えたほうが良いです。CreateInstanceメソッドとかでインスタンスを作成したら、あとは普通のインスタンスとしてメソッドを普通に呼び出しましょう(インスタンスを作成したらそれはTESTLインターフェースにキャスト可能のはず)

http://dobon.net/vb/dotnet/programing/plugin.html
みなさん、回答ありがとうございます。

CreateInstanceの方がわかりやすいですね。
というわけでやってみましたが、ダメでしたToT
なぜでしょうね?ToT CreateInstanceの結果がnullになって
います。

1.LoadFileで指定しているファイルパスは正しいです。
2.CreateInstance指定のクラス名は正しいです。
3.動的に読み込みさせているので、TESTL01.dllには参照
 設定はしていない。
4.エラー内容からすると"クラスが参照できない"のが原因
 と出ている。

■エラー内容
この参照を解決できませんでした。
アセンブリ "TESTL01, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"
が見つかりませんでした。アセンブリが間違いなくディスクに存在することを確認してくだ
さい。
コードにこの参照が必要な場合、コンパイル エラーが発生する可能性があります。
TestApplication

■実行プログラム
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;

namespace TestApplication
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
Assembly asm = Assembly.LoadFile("C:\\sample\\bin\\TESTL01.dll");

Object obj = asm.CreateInstance("com.hoge.sample.TESTL01");

MessageBox.Show(obj.GetType().Name);
}
自己レスです。getInstanceでググって調べてみたところ、
なんとかできました!!
2パターンできまして、1つは先程のやり方と同じです・・・。
※さっきのがなぜできなかったのか不思議です・・・

2つの違いは、Typeオブジェクトを使用するか直接クラス名
のまま使用するかと、getInstanceを使用しているクラスが
異なることですね。どちらが一般的なんでしょうか?

■参考
http://www.atmarkit.co.jp/fdotnet/dotnettips/386createinstance/createinstance.html


■実行プログラム
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;

namespace TestApplication
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
Assembly asm = Assembly.LoadFile("C:\\sample\\bin\\TESTL01.dll");

Object obj = asm.CreateInstance("com.hoge.sample.TESTL01");

TESTL sp = (TESTL)obj1;

sp.exec();
}


private void button2_Click(object sender, EventArgs e)
{
Assembly asm = Assembly.LoadFile("C:\\sample\\bin\\TESTL01.dll");

Type t = asm.GetType("com.hoge.sample.TESTL01");

Object obj1 = Activator.CreateInstance(t);

TESTL sp = (TESTL)obj1;

sp.exec();
}

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

C# 更新情報

C#のメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング