2012-05-07 2 views
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 

Это связано с WCF, где один должен предоставить CreateHost единственный класс, который реализует все интерфейсы, необходимые для конечных точек. В этом случае ActionDispatcher является таким классом, и IAction является одним из многих интерфейсов, которые должны быть реализованы.

Мое видение заключается в том, чтобы не выполнять IAction в ActionDispatcher вручную, но иметь какой-то механизм регистрации, где я могу сказать, что ActionDispatcher должен реализовывать интерфейсы IAction, IDoing, INoAction и т. Д. - и для меня созданы методы диспетчеризации.

MSDN говорит, что любой класс совместим с любым интерфейсом, поэтому мне не нужно объявлять «Реализует» в ActionDispatcher. Но мне все еще нужно реализовать интерфейс и подключить метод реализации к определению интерфейса, поэтому WCF может найти его при необходимости.

Ближайшая вещь, которую я нашел, вероятно, Automatic Interface Implementer, но она (1) создает новый тип, (2) добавляет фиктивные методы.

Я также попытался понять класс CodeCompileUnit, но до сих пор не видел отношения к тому, что мне нужно.

Может ли кто-нибудь более опытный в Reflection API помочь мне? Есть ли хороший способ сделать то, что я хочу?

+0

Я прохожу через это упражнение. Я предполагаю, что мне больше всего хотелось бы не общаться с IL (что само собой разумеется, как ассемблер, а также с большей склонностью к ошибкам), но генерировать IL-код из строки :-) Что-то вроде Compiler.CompileToIL("Public Sub DoThat(a As Integer) Implements ... End Sub") MikNik

ответ

2

Я, наконец, хрустел. Для тех, кто заинтересован в intrications, решение (вкратце):

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, чтобы свести к минимуму количество сгенерированного кода.

0

Во-первых, это похоже на много работы, пытаясь избежать нескольких строк кода. Если вы хотите, чтобы класс реализовал интерфейс, просто укажите, как работает система типа .Net.

И на самом деле вы не можете делать то, что хотите. Вы не можете изменить код класса во время выполнения. Лучшее, на что вы можете надеяться, это создать новый тип, реализующий интерфейс. Но если вы не хотите создавать новые типы во время выполнения (почему?), То я думаю, вам не повезло.

+0

Я исследовал его немного дальше. Вы правы, создание новых типов во время выполнения - мой единственный выход. Почему? Ну, мне нравится автоматика :-) Добавление нового интерфейса должно быть настолько безболезненным, что, возможно, отделяет его от всего возможного, это моя цель. – MikNik

+0

Но не имеет смысла отделять интерфейсы от классов. Когда вы пишете класс, вам нужно знать о интерфейсах, которые он собирается реализовать, чтобы узнать, какие члены должны реализовывать (и как), поэтому вы можете точно указать интерфейс явно. – svick

+0

Почему бы и нет? Если у вас есть 50 интерфейсов для реализации, вы не хотите делать много дублированного кода. Если я просто предоставляю список интерфейсов для реализации, и он выполняет эту работу - это более надежный. – MikNik

0

Я слышал о записи значений свойств с помощью отражения, но вводил новые свойства и методы в существующий тип во время выполнения? Звучит слишком футуристически для меня.

Даже если это было возможно, интерфейсы используются для определения набора свойств и/или методов, которые всегда присутствуют в типе, который их реализует. Если вы действительно можете добавить или удалить реализации по своему усмотрению, это, скорее всего, сломает любой другой тип, который так или иначе будет полагаться на ваш класс.

Смежные вопросы