如何以编程方式(在运行时)向类添加接口

时间:2012-05-07 12:29:12

标签: .net vb.net reflection interface

我正在寻找一种在运行时向类添加接口实现的方法。 这是一个示例代码,我将在下面讨论。

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

这与WCF有关,其中需要向CreateHost提供单个类,该类实现端点所需的所有接口。在这种情况下,ActionDispatcher就是这样一个类,而IAction是要实现的众多接口之一。

我的目标是避免手动在ActionDispatcher中实现IAction,但我可以说有一些注册机制,ActionDispatcher必须实现接口IAction,IDoing,INoAction等 - 并为我生成调度方法。 / p>

MSDN说,任何类都与任何接口兼容,所以我不需要在ActionDispatcher中声明“Implements”。但是我仍然需要实现接口并将实现方法连接到接口定义,因此WCF可以在需要时找到它。

我找到的最接近的东西可能是Automatic Interface Implementer,但它(1)创建了一个新类型,(2)添加了虚拟方法。

我也尝试了解CodeCompileUnit类,但到目前为止还看不到与我需要的关系。

在Reflection API中有经验的人可以帮助我吗?有什么好方法可以做我想要的吗?

4 个答案:

答案 0 :(得分: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的中间函数,以最小化生成的代码量。

答案 1 :(得分:0)

首先,这似乎是在尝试避免几行代码的大量工作。如果你想让一个类实现一个接口,只需指定一下,这就是.Net类型系统的工作方式。

实际上,你不能真正做你想做的事。您无法在运行时修改类的代码。您可以期望的最好的方法是创建一个实现接口的新类型。但是如果你不想在运行时创建新类型(为什么?),那么我认为你运气不好。

答案 2 :(得分:0)

我听说过使用反射编写属性值,但是在运行时将新属性和方法注入现有类型?对我来说听起来有点太未来了。

即使可能,接口也用于定义一组在实现它们的类型中始终的属性和/或方法。如果您确实可以随意添加或删除实现,那么它很可能会破坏以某种方式依赖于您的类的任何其他类型。

答案 3 :(得分:0)

您可以使用Castle Dynamic Proxy尝试某种混音。 http://www.codeproject.com/Articles/9055/Castle-s-DynamicProxy-for-NET 但是也会创建一个新类型(代理),所以也许你不喜欢它......