C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[2]: プラグイン実装方法について


(過去ログ 63 を表示中)

[トピック内 17 記事 (1 - 17 表示)]  << 0 >>

■36374 / inTopicNo.1)  プラグイン実装方法について
  
□投稿者/ SSR (1回)-(2009/05/28(Thu) 09:00:53)

分類:[VB.NET/VB2005 以降] 

OS:Vista
言語:VB2008

いつもお世話になっております。
今回は、実装方法についてご教授下さい。
内容は以下の通りです。

「文字列を引数として渡すと、構造体を返す関数を作成する。」

具体的な目的はこれなのですが、
「構造体」が複数あり、後々追加もあるので
「関数」をプラグインとして作成し、
拡張性を持たせようと考えています。

頭の中では、「関数」のインターフェースと
「構造体」の基底クラスがあれば、
プラグインの中の派生クラスで返してくる「構造体」を取得することが
可能かと思ったのですが…。

「構造体」の一部の値(基底クラス部分)を取得出来れば
後はプラグインの要素を取得すれば構造体全体が見えると
判断したのです。

ところが、この方法では「関数」の返り値を基底クラスの型でキャストできません。

この実装方法は無理があるのでしょうか?
若輩に指導をお願いします。
インターフェースやクラスの継承、プラグインの考え方が違う場合も、
遠慮なくご指摘下さい。


引用返信 編集キー/
■36375 / inTopicNo.2)  Re[1]: プラグイン実装方法について
□投稿者/ aetos (146回)-(2009/05/28(Thu) 09:46:03)
No36374 (SSR さん) に返信
> ところが、この方法では「関数」の返り値を基底クラスの型でキャストできません。

というのが、具体的にどういう障害によって引っかかっているのかわかりません。
コンパイルエラー等出るのでしたら、エラーメッセージを載せてください。

ちなみに、構造体は継承できません。
継承する必要があるならクラスにします。
引用返信 編集キー/
■36377 / inTopicNo.3)  Re[1]: プラグイン実装方法について
□投稿者/ aetos (147回)-(2009/05/28(Thu) 09:50:33)
No36374 (SSR さん) に返信

なお、.NET Framework が標準でアドイン機能をサポートする API を持っています。
System.AddIns 名前空間以下にあります。

プロトコルが変わった場合の対応やセキュリティ、パフォーマンスも考慮して柔軟にできていますが、その分、大仰になってしまっている印象ですが。
引用返信 編集キー/
■36386 / inTopicNo.4)  Re[2]: プラグイン実装方法について
□投稿者/ SSR (2回)-(2009/05/28(Thu) 11:13:05)
No36375 (aetos さん) に返信
> ■No36374 (SSR さん) に返信
>>ところが、この方法では「関数」の返り値を基底クラスの型でキャストできません。
>
> というのが、具体的にどういう障害によって引っかかっているのかわかりません。
> コンパイルエラー等出るのでしたら、エラーメッセージを載せてください。

すみません、エラーメッセージです。
System.IndexOutOfRangeException: インデックスが配列の境界外です。


> ちなみに、構造体は継承できません。
> 継承する必要があるならクラスにします。

そうです。「構造体」とは、クラスです。
説明不足ですみません…。




No36377 (aetos さん) に返信
> ■No36374 (SSR さん) に返信
>
> なお、.NET Framework が標準でアドイン機能をサポートする API を持っています。
> System.AddIns 名前空間以下にあります。
>
> プロトコルが変わった場合の対応やセキュリティ、パフォーマンスも考慮して柔軟にできていますが、その分、大仰になってしまっている印象ですが。


おお!新しい!
早速調べて、結果を報告します。ありがとうございます!!
引用返信 編集キー/
■36392 / inTopicNo.5)  Re[3]: プラグイン実装方法について
□投稿者/ YuO (1回)-(2009/05/28(Thu) 12:00:16)
No36386 (SSR さん) に返信
> System.IndexOutOfRangeException: インデックスが配列の境界外です。

これは,
Dim n(10) As Integer
とあった時に,
n(11) = 20
とかやった場合に起きる例外です (キャストとは無関係です)。
例外が起きたタイミングでの,配列の大きさとインデックスの値をチェックしてみてはどうでしょうか。
引用返信 編集キー/
■36394 / inTopicNo.6)  Re[4]: プラグイン実装方法について
□投稿者/ SSR (3回)-(2009/05/28(Thu) 12:39:32)
No36392 (YuO さん) に返信
> ■No36386 (SSR さん) に返信
>>System.IndexOutOfRangeException: インデックスが配列の境界外です。
>
> これは,
> Dim n(10) As Integer
> とあった時に,
> n(11) = 20
> とかやった場合に起きる例外です (キャストとは無関係です)。
> 例外が起きたタイミングでの,配列の大きさとインデックスの値をチェックしてみてはどうでしょうか。


わわ!!すみません、プラグイン指定間違ってました!
エラー違いです!

System.InvalidCastException: 型 'structA' のオブジェクトを型 'stA' にキャストできません。

structAは派生クラス、stAは基底クラスです。
シリアライズ、デシリアライズは同じ発想で出来るのですが…

AddInは何がどう出来るのか、調査中です。




引用返信 編集キー/
■36396 / inTopicNo.7)  Re[5]: プラグイン実装方法について
□投稿者/ Hongliang (400回)-(2009/05/28(Thu) 13:03:25)
> System.InvalidCastException: 型 'structA' のオブジェクトを型 'stA' にキャストできません。
>
> structAは派生クラス、stAは基底クラスです。
> シリアライズ、デシリアライズは同じ発想で出来るのですが…

stA クラスをそれぞれで定義してますかね。
型はアセンブリ(dll/exe)情報も含んで識別されますので、名前が同じでもアセンブリが別なら別の型です。
引用返信 編集キー/
■36405 / inTopicNo.8)  Re[6]: プラグイン実装方法について
□投稿者/ SSR (4回)-(2009/05/28(Thu) 15:51:29)
No36396 (Hongliang さん) に返信
>>System.InvalidCastException: 型 'structA' のオブジェクトを型 'stA' にキャストできません。
>>
>>structAは派生クラス、stAは基底クラスです。
>>シリアライズ、デシリアライズは同じ発想で出来るのですが…
>
> stA クラスをそれぞれで定義してますかね。

はい、インターフェースを継承し、それぞれのプラグイン用.dllに定義してあります。


> 型はアセンブリ(dll/exe)情報も含んで識別されますので、名前が同じでもアセンブリが別なら別の型です。

すみません、よく理解出来ませんでした…。

「型は、アセンブリ情報を含んでいる」
ということは、A.exeのString型変数はB.exeでString型変数として認識出来ない
ということでしょうか??




引用返信 編集キー/
■36412 / inTopicNo.9)  Re[7]: プラグイン実装方法について
□投稿者/ 魔界の仮面弁士 (1101回)-(2009/05/28(Thu) 16:50:01)
2009/05/28(Thu) 16:50:37 編集(投稿者)

No36405 (SSR さん) に返信
>> stA クラスをそれぞれで定義してますかね。
> はい、インターフェースを継承し、
継承(Inherits)ですか? 実装(Implements)ではなく?

> それぞれのプラグイン用.dllに定義してあります。
そのインターフェイスの定義は、どこで行われていますか?

stA クラスは、それぞれの DLL にて定義しても良いですが、
元となるインターフェイスは、それぞれに定義してはマズイです。

たとえ、名前空間/型名/メンバ定義などが一緒だったとしても、
「Project1 アセンブリの Hoge.IFoo インターフェイス」と
「Project2 アセンブリの Hoge.IFoo インターフェイス」は、
それぞれ別の型として扱われる事になりますので。


> 「型は、アセンブリ情報を含んでいる」
> ということは、A.exeのString型変数はB.exeでString型変数として認識出来ない
> ということでしょうか??
String 型とは、「mscorlib アセンブリの System.String クラス」ですよね。
A.exe でも B.exe でも、それは変わりません。
引用返信 編集キー/
■36416 / inTopicNo.10)  Re[8]: プラグイン実装方法について
□投稿者/ SSR (6回)-(2009/05/28(Thu) 17:52:10)
No36412 (魔界の仮面弁士 さん) に返信
> 2009/05/28(Thu) 16:50:37 編集(投稿者)
>
> ■No36405 (SSR さん) に返信
> >> stA クラスをそれぞれで定義してますかね。
>>はい、インターフェースを継承し、
> 継承(Inherits)ですか? 実装(Implements)ではなく?
>
>>それぞれのプラグイン用.dllに定義してあります。
> そのインターフェイスの定義は、どこで行われていますか?
>
> stA クラスは、それぞれの DLL にて定義しても良いですが、
> 元となるインターフェイスは、それぞれに定義してはマズイです。
>
> たとえ、名前空間/型名/メンバ定義などが一緒だったとしても、
> 「Project1 アセンブリの Hoge.IFoo インターフェイス」と
> 「Project2 アセンブリの Hoge.IFoo インターフェイス」は、
> それぞれ別の型として扱われる事になりますので。


魔界の仮面弁士さん。 いつもいつもすみません。
どうやら私の知識と説明がおかしい様なので、
再度、現在のクラス設計から説明し直します。


1.プラグイン用のインターフェイスであるIPluginがあります。
この中には、プラグイン名のプロパティと、
文字列を変換するメソッドがあります。


2.文字列を格納する構造体の基底クラスstAがあります。


3.更に、IPluginインターフェイスを実装(Implements)した、MakeStructクラスがあります。
このクラスにはプラグイン名と、文字列変換メソッドと
stAクラスを継承(Inherits)したstructAクラスがあります。


4.文字列をMakeStruct.dllプラグインを使用して、structAを受け取るForm1があります。

エラーはこのForm1の部分で起きています。
(基底クラスを参照し、取得しようとしました。)
当然、型は違うので、キャスト出来ません。
今になってみれば、何故基底クラスなら取得出来ると判断したのかわかりません…

リフレクションでプラグインの要素を取得しようにも
動的に変化するオブジェクトの型を、どうやって生成すればいいのか…


>>「型は、アセンブリ情報を含んでいる」
>>ということは、A.exeのString型変数はB.exeでString型変数として認識出来ない
>>ということでしょうか??
> String 型とは、「mscorlib アセンブリの System.String クラス」ですよね。
> A.exe でも B.exe でも、それは変わりません。


おおおお…そうなのですか。
私は、何か間違って解釈しているようですね…

追記:AddInsなのですが、今の私にはまだ敷居が高いようです。
もう少し、調べてみます。
引用返信 編集キー/
■36417 / inTopicNo.11)  Re[2]: プラグイン実装方法について
□投稿者/ なちゃ (284回)-(2009/05/28(Thu) 18:08:16)
なんかソース出した方が早いかも。
説明し直してもらってもやっぱりどうなってるのかよく分かりません。
ちょっと用語の使い方やら正確ではなさそうですし。

引用返信 編集キー/
■36419 / inTopicNo.12)  Re[3]: プラグイン実装方法について
□投稿者/ SSR (8回)-(2009/05/28(Thu) 18:57:12)
No36417 (なちゃ さん) に返信
> なんかソース出した方が早いかも。
> 説明し直してもらってもやっぱりどうなってるのかよく分かりません。
> ちょっと用語の使い方やら正確ではなさそうですし。

すみません、ソース出します。
現在のソースは、いろんなことに手を出してしまって汚いので、
初期のころのソースを簡略化して出します。
今とはちょっと用語が違うかもしれませんが、構成は一緒です。

1.IPluginインターフェイス

Public Interface IPlugin
ReadOnly Property Name() As String 'プラグイン名
Function Run(ByVal str As String) As Object 'プラグイン機能
End Interface


2.clsStructクラス(stAクラス)

Public Class clsStruct
Public str01 As String
Public str02 As String
End Class


3.StructChar.dll(MakeStruct.dll)

Imports IPlugin
Public Class StructChar
Implements IPlugin.IPlugin

'プラグイン名
Public ReadOnly Property Name1() As String Implements IPlugin.IPlugin.name
Get
Return "文字列変換"
End Get
End Property

'プラグイン機能
Public Function Run1(ByVal str As String) As Object Implements IPlugin.IPlugin.Run
Dim st1 As New st

st1.str01 = Left(str, 1)
st1.str02 = Left(str, 5)
st1.str03 = str

Return st1

End Function

'変換クラス
Public Class
Inherits clsStruct
Public str03 As String
End Class

End Class


4.


Imports IPlugin
Public Class PluginForm1

'プラグイン
Private plugins() As IPlugin.IPlugin

Class sttarm
Inherits clsStruct
End Class

Private Sub PluginForm1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles MyBase.Load

'インストールされているプラグインを調べる
Dim pis As PluginInfo() = PluginInfo.FindPlugins()

'すべてのプラグインクラスのインスタンスを作成する
For i As Integer = 0 To pis.Length - 1
ReDim plugins(i)
plugins(i) = pis(i).CreateInstance()
Next i

End Sub

Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click

Dim str As String = "0123456789"

Dim stA As sttarm = CType(plugins(0).Run(str), sttarm)
MessageBox.Show(stA.str01)

End Sub

End Class

追記:http://codezine.jp/article/detail/1?p=1を参考に作っております。
というか、丸写しです。

引用返信 編集キー/
■36421 / inTopicNo.13)  Re[4]: プラグイン実装方法について
□投稿者/ 魔界の仮面弁士 (1104回)-(2009/05/28(Thu) 19:19:12)
[図表モード]での投稿をお願いします。

No36419 (SSR さん) に返信
> 1.IPluginインターフェイス
> Public Interface IPlugin
>  ReadOnly Property Name() As String 'プラグイン名
>  Function Run(ByVal str As String) As Object 'プラグイン機能
> End Interface
As Object ではなく、プラグインで共有される「インターフェイス」または「抽象クラス」を
返すようにしてください。


> 2.clsStructクラス(stAクラス)
このクラスは、どのアセンブリで定義されているのでしょうか?

> 3.StructChar.dll(MakeStruct.dll)
IPlugin は、旧StructChar.dll(現MakeStruct.dll)内で定義されているのでしょうか。
それとも、他の DLL で定義されているのでしょうか。


> 4.
> Imports IPlugin
> Public Class PluginForm1
これは、StructChar.dll とは別のアセンブリですか?
それとも、同一アセンブリ上に定義されているのでしょうか?

> Private plugins() As IPlugin.IPlugin
> Dim pis As PluginInfo() = PluginInfo.FindPlugins()
配列の定義方法が、
 Dim X() As Y
 Dim X As Y()
との間で揺れています。意味は同じですが、表記は統一しておいた方がよろしいかと。


> For i As Integer = 0 To pis.Length - 1
>  ReDim plugins(i)
>  plugins(i) = pis(i).CreateInstance()
> Next i
ReDim を行うと、配列の中身はクリアされてしまいます。この場合は、
 ReDim plugins(pis.Length - 1)
 For i As Integer = 0 To pis.Length - 1
  plugins(i) = pis(i).CreateInstance()
 Next i
と書いてください。(Preserve を使う事もできますが、先に確保しておいた方が効率が良いです)


> Dim str As String = "0123456789"
> Dim stA As sttarm = CType(plugins(0).Run(str), sttarm)
逆ですよ。
 Dim x As 基本クラスまたはインターフェイス = プラグイン.Run(xxx)
とするべきかと。

例えば、
 Dim x As Form = 別ライブラリ.GetForm()
はできますが、
 Dim x As 自EXE上で定義したForm1 = 別ライブラリ.GetForm()
はできません。
引用返信 編集キー/
■36426 / inTopicNo.14)  Re[5]: プラグイン実装方法について
□投稿者/ SSR (10回)-(2009/05/28(Thu) 21:17:05)
> [図表モード]での投稿をお願いします。

すみません。投稿してから気付きました。
次から気をつけます。


> ■No36419 (SSR さん) に返信
>>1.IPluginインターフェイス
>>Public Interface IPlugin
>> ReadOnly Property Name() As String 'プラグイン名
>> Function Run(ByVal str As String) As Object 'プラグイン機能
>>End Interface
> As Object ではなく、プラグインで共有される「インターフェイス」または「抽象クラス」を
> 返すようにしてください。


ありがとうございます。了解しました。

Object→clsStruct
に修正します。



>>2.clsStructクラス(stAクラス)
> このクラスは、どのアセンブリで定義されているのでしょうか?


IPluginプロジェクトです。

IPlugin.IPlugin
IPlugin.clsStruct
という階層になっております。


>>3.StructChar.dll(MakeStruct.dll)
> IPlugin は、旧StructChar.dll(現MakeStruct.dll)内で定義されているのでしょうか。
> それとも、他の DLL で定義されているのでしょうか。


他のDLLです。


>>4.
>>Imports IPlugin
>>Public Class PluginForm1
> これは、StructChar.dll とは別のアセンブリですか?
> それとも、同一アセンブリ上に定義されているのでしょうか?


別のアセンブリです。


>>Private plugins() As IPlugin.IPlugin
>>Dim pis As PluginInfo() = PluginInfo.FindPlugins()
> 配列の定義方法が、
>  Dim X() As Y
>  Dim X As Y()
> との間で揺れています。意味は同じですが、表記は統一しておいた方がよろしいかと。


すみません。ありがとうございます。
ソースレビューみたいになってしまいましたが、
実際にレビューを受けるのは初めてなので勉強になります。



>>For i As Integer = 0 To pis.Length - 1
>> ReDim plugins(i)
>> plugins(i) = pis(i).CreateInstance()
>>Next i
> ReDim を行うと、配列の中身はクリアされてしまいます。この場合は、
>  ReDim plugins(pis.Length - 1)
>  For i As Integer = 0 To pis.Length - 1
>   plugins(i) = pis(i).CreateInstance()
>  Next i
> と書いてください。(Preserve を使う事もできますが、先に確保しておいた方が効率が良いです)


そうでした!!
気をつけます。


>>Dim str As String = "0123456789"
>>Dim stA As sttarm = CType(plugins(0).Run(str), sttarm)
> 逆ですよ。
>  Dim x As 基本クラスまたはインターフェイス = プラグイン.Run(xxx)
> とするべきかと。
>
> 例えば、
>  Dim x As Form = 別ライブラリ.GetForm()
> はできますが、
>  Dim x As 自EXE上で定義したForm1 = 別ライブラリ.GetForm()
> はできません。


Dim x As 基本クラスまたはインターフェイス = プラグイン.Run(xxx)
おかげさまでようやく理解できました。ありがとうございます。

例えば、
Dim x As Form = 別ライブラリ.GetForm()
別ライブラリで定義されたForm1型は、Form型として受け取る。

xからForm1にある、独自のコンポーネントにアクセスするためにはどうしたらよろしいでしょうか?




引用返信 編集キー/
■36458 / inTopicNo.15)  Re[6]: プラグイン実装方法について
□投稿者/ 魔界の仮面弁士 (1109回)-(2009/05/29(Fri) 10:23:00)
No36426 (SSR さん) に返信
> Dim x As Form = 別ライブラリ.GetForm()
> 別ライブラリで定義されたForm1型は、Form型として受け取る。
> xからForm1にある、独自のコンポーネントにアクセスするためにはどうしたらよろしいでしょうか?

ベースクラス(あるいはインターフェイス)のメンバを通じてアクセスするようにしてください、

例えば、
 Dim x As IHoge = ライブラリA.GetHoge()
として、GetHoge から「IHoge を Implements した Class1 クラス」のインスタンスが返される場合、
受け取り側は、「IHoge のメンバ」のみを通じて、そのクラスを操作することになります。

リフレクションを使えば、Class1 のメンバを扱うこともできますが、それをしてはいけません。
(そうすると、呼び出し側はプラグインごとに異なる処理を記述しなければいけなくなってしまいますので)
引用返信 編集キー/
■36465 / inTopicNo.16)  Re[1]: プラグイン実装方法について
□投稿者/ たくボン (164回)-(2009/05/29(Fri) 11:34:05)
No36374 (SSR さん) に返信
> OS:Vista
> 言語:VB2008
> 「文字列を引数として渡すと、構造体を返す関数を作成する。」
>
> 具体的な目的はこれなのですが、
> 「構造体」が複数あり、後々追加もあるので
> 「関数」をプラグインとして作成し、
> 拡張性を持たせようと考えています。

ざっとしか読んでないけど、デザインパターンのfactoryやbuilderの辺りを勉強すれば幸せになれると思う。
引用返信 編集キー/
■36492 / inTopicNo.17)  Re[2]: プラグイン実装方法について
□投稿者/ SSR (11回)-(2009/05/29(Fri) 20:16:12)
No36458 (魔界の仮面弁士 さん) に返信
> ■No36426 (SSR さん) に返信
>>Dim x As Form = 別ライブラリ.GetForm()
>>別ライブラリで定義されたForm1型は、Form型として受け取る。
>>xからForm1にある、独自のコンポーネントにアクセスするためにはどうしたらよろしいでしょうか?
>
> ベースクラス(あるいはインターフェイス)のメンバを通じてアクセスするようにしてください、
>
> 例えば、
>  Dim x As IHoge = ライブラリA.GetHoge()
> として、GetHoge から「IHoge を Implements した Class1 クラス」のインスタンスが返される場合、
> 受け取り側は、「IHoge のメンバ」のみを通じて、そのクラスを操作することになります。


> リフレクションを使えば、Class1 のメンバを扱うこともできますが、それをしてはいけません。
> (そうすると、呼び出し側はプラグインごとに異なる処理を記述しなければいけなくなってしまいますので)

そうですね!
せっかく拡張性を持たせようとしているのに、これでは意味が無いですね。


ベースクラスや、インターフェースを通じてでは、
全ての要素に正確にアクセス出来ないという問題がありました。

そこで、
今までキャストできなかった部分をシリアライズし、バイト配列で受け渡し
エンドアプリケーションが、デシリアライズを行うことで
正確に要素にアクセスすることが出来ました。

(元々、アプリケーション間のデータのやり取りをソケット通信で行う予定でした)
ちなみに、このアイディアは私ではなく先輩です。



No36465 (たくボン さん) に返信
> ■No36374 (SSR さん) に返信
>>OS:Vista
>>言語:VB2008
>>「文字列を引数として渡すと、構造体を返す関数を作成する。」
>>
>>具体的な目的はこれなのですが、
>>「構造体」が複数あり、後々追加もあるので
>>「関数」をプラグインとして作成し、
>>拡張性を持たせようと考えています。
>
> ざっとしか読んでないけど、デザインパターンのfactoryやbuilderの辺りを勉強すれば幸せになれると思う。


ありがとうございます。
調べてみます。

今回、様々な問題に当たって、自分の知識の曖昧さや、勉強不足を強く感じました。

最後まで親切にご指導下さった皆様に感謝します。
また、よろしくお願い致します。



解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -