1

実行時にクラスにインターフェース実装を追加する方法を探しています。これがサンプルコードです。これについては以下で説明します。

Public Interface IAction
    Sub DoThis(a As Integer)
End Interface


Class Actor
Implements IAction

    Private mNumber As Integer

    Public Sub New(number As Integer)
        mNumber = number
    End Sub

    Public Sub DoThis(a As Integer) Implements IAction.DoThis
        Console.WriteLine(String.Format("Actor #{0}: {1}", mNumber, a))
    End Sub

End Class


Class ActionDispatcher
Implements IAction

    Private Shared mActionList As New List(Of IAction)

    Public Shared Sub Add(actor As IAction)
        mActionList.Add(actor)
    End Sub

    Public Sub DoThis(a As Integer) Implements IAction.DoThis
        For Each act In mActionList
            act.DoThis(a)
        Next
    End Sub

End Class


Module Module1

    Sub Main()
        Dim a As New ActionDispatcher
        ActionDispatcher.Add(New Actor(1))
        ActionDispatcher.Add(New Actor(2))
        a.DoThis(5)
    End Sub

End Module

これは、エンドポイントに必要なすべてのインターフェイスを実装する単一のクラスをCreateHostに提供する必要があるWCFに関連しています。このシナリオでは、ActionDispatcherはそのようなクラスであり、IActionは実装される多くのインターフェースの1つです。

私のビジョンは、ActionDispatcherでIActionを手動で実装することを避けることですが、何らかの登録メカニズムがあり、ActionDispatcherはインターフェイスIAction、IDoing、INoActionなどを実装する必要があり、ディスパッチメソッドを生成する必要があります。

MSDNによると、どのクラスもどのインターフェイスとも互換性があるため、ActionDispatcherで「Implements」を宣言する必要はありません。ただし、インターフェイスを実装し、実装メソッドをインターフェイス定義に接続する必要があるため、WCFは必要なときにそれを見つけることができます。

私が見つけた最も近いものはおそらく自動インターフェース実装者ですが、(1)新しいタイプを作成し、(2)ダミーメソッドを追加します。

また、CodeCompileUnitクラスを理解しようとしましたが、これまでのところ、必要なものとの関係を確認できませんでした。

Reflection APIの経験が豊富な人が私を助けてくれますか?私がやりたいことをする良い方法はありますか?

4

4 に答える 4

2

私はついにそれを砕いた。複雑さに興味がある人のために、解決策(要するに)は次のとおりです:

Class ActionDispatcher

    Private Shared mImplementorType As Type

    Public Shared Function GetImplementorType() As Type
        If mImplementorType Is Nothing
            mImplementorType = CreateImplementorType()
        End If

        Return mImplementorType
    End Function

    Private Shared Function CreateImplementorType() As Type
        ' Nice to have RunAndSave for debugging with ILdasm / ILSpy
        Dim myAssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
            New AssemblyName() With { .Name = "ViewerDispatcherAssembly" },
            AssemblyBuilderAccess.RunAndSave)
        Dim mbuilder = myAssemblyBuilder.DefineDynamicModule("ViewerDispatcherModule", "ViewerDispatcherModule.dll")
        Dim tbuilder = mbuilder.DefineType("ViewerDispatcherImpl", TypeAttributes.Class Or TypeAttributes.Public)

        For Each itype In mInterfaceTypes
            tbuilder.AddInterfaceImplementation(itype)
            For Each method In itype.GetMethods()
                ' Create interface implementation for each interface method.
                CreateInterfaceImplementation(tbuilder, itype, method, capability, mbuilder)
            Next
        Next
        Return tbuilder.CreateType()
    End Sub
End Class

この関数は、インターフェイスパラメータを保持するタイプと、正しい関数CreateInterfaceImplementationを呼び出すためのこのタイプのメソッドを動的に作成します。IActionまた、でIAction実装を作成しtbuilderます。mActionList生成されるコードの量を最小限に抑えるためにループする中間関数もあります。

于 2012-05-10T13:07:25.170 に答える
0

リフレクションを使用してプロパティ値を書き込むことを聞いたことがありますが、実行時に既存の型に新しいプロパティとメソッドを挿入しますか?私には少し未来的すぎるように聞こえます。

可能であったとしても、インターフェースは、それらを実装するタイプに常に存在する一連のプロパティやメソッドを定義するために使用されます。実際に実装を自由に追加または削除できれば、クラスに何らかの形で依存している他のタイプを壊してしまう可能性があります。

于 2012-05-07T16:39:47.007 に答える
0

まず、これは数行のコードを回避しようとする多くの作業のようです。クラスにインターフェースを実装させたい場合は、それを指定するだけで、.Net型システムが機能します。

そして実際には、あなたは本当にあなたが望むことをすることはできません。実行時にクラスのコードを変更することはできません。期待できる最善の方法は、インターフェイスを実装する新しいタイプを作成することです。しかし、実行時に新しい型を作成したくない場合(なぜですか?)、運が悪いと思います。

于 2012-05-07T12:42:40.837 に答える
0

CastleDynamicProxyを使用してある種のミックスインを試すことができます。 http://www.codeproject.com/Articles/9055/Castle-s-DynamicProxy-for-NET ただし、新しいタイプ(プロキシ)も作成されるため、どちらも気に入らないかもしれません。

于 2012-05-07T21:44:10.207 に答える