2009-03-13 22 views
0

Ich habe folgendes Problem mit MEF:Casting-Schnittstellen und MEF

Public Interface IExecuteDoSomething 
    Inherits IAddinSettings 

    Event DataReceived As EventHandler(Of DataReceivedEventArgs) 
    Function DoSomething() As Boolean 

End Interface 

Public Class DataReceivedEventArgs 
    Inherits EventArgs 

    Public Sub New(ByVal message As String) 
     Me.Message = message 
    End Sub 

    Public Message As String 
End Class 

zusätzliche Schnittstelle durch einen anderen Code innerhalb der Host benötigt:

Public Interface IAddinSettings 
     ReadOnly Property Setting() As AddinSettings 
    End Interface 

    Public Class AddinSettings 
     Private _Name As String 
     Public Property Name() As String 
      Get 
       Return _Name 
      End Get 
      Set(ByVal value As String) 
       _Name = value 
      End Set 
     End Property 

     Public Sub New(ByVal name As String) 
      Me.Name = name 
     End Sub 
    End Class 

Schnittstelle Definition von Host verwendet werden

Die Klasse, die den Export bereitstellt:

<Export(GetType(SharedLibrary.IExecuteDoSomething))> Public Class Class1 
     Implements SharedLibrary.IExecuteDoSomething 
     Implements SharedLibrary.IAddinSettings 

     Private _Addinsettings As New SharedLibrary.Addinsettings("Test") 

     Public Function DoSomething() As Boolean Implements SharedLibrary.IExecuteDoSomething.DoSomething 
      MsgBox("i did something") 
      Return True 
     End Function 


     Public Event DataReceived(ByVal sender As Object, ByVal e As SharedLibrary.DataReceivedEventArgs) Implements SharedLibrary.IExecuteDoSomething.DataReceived 

     Public ReadOnly Property Setting() As SharedLibrary.AddinSettings Implements SharedLibrary.IAddinSettings.Setting 
      Get 
       Return _Addinsettings 
      End Get 
     End Property 
    End Class 

Gastgeber:

Public Class Form1 

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
     Dim catalog As New Hosting.AggregateCatalog 
     Dim d As New Hosting.DirectoryCatalog("..path to dlll..") 
     catalog.Catalogs.Add(d) 
     Dim container = New Hosting.CompositionContainer(catalog) 
     Dim batch As New Hosting.CompositionBatch 
     batch.AddPart(Me) 
     container.Compose(batch) 
     For Each dd In dos 
      AddHandler dd.DataReceived, AddressOf testevent 
     Next 
    End Sub 

    <Import()> Public dos As IEnumerable(Of SharedLibrary.IExecuteDoSomething) 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
     For Each d In dos 
      d.DoSomething() 
     Next 
    End Sub 

    Private Sub testevent(ByVal sender As Object, ByVal e As SharedLibrary.DataReceivedEventArgs) 
     MsgBox("Event received: " & e.Message) 
    End Sub 

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click 
     Dosomethingelse(DirectCast(dos, System.Collections.Generic.List(Of SharedLibrary.IAddinSettings))) 
    End Sub 
    Private Sub Dosomethingelse(byval settings as IEnumerable(Of SharedLibrary.IAddinSettings)) 
    End Sub 

End Class 

Alles scheint gut zu funktionieren, bis die Button2_Click Routine ausgeführt wird, dann wird eine InvalidCastException mit der Info geworfen wird:
kann nicht 1[SharedLibrary.IExecuteDoSomething]' to type 'System.Collections.Generic.List Objekte vom Typ ‚System.Collections.Generic.List werfen 1 [SharedLibrary.IAddinSettings] '.

Wie kann ich dieses Problem lösen, weil das importierte Objekt beide Schnittstellen implementiert?

Antwort

1

Ich vermute, dass Sie tatsächlich in ein Kovarianz-Problem geraten - das ist die typische Ursache für solche Probleme. A List<IFoo> ist nicht ein List<IBar> auch wenn IBar erweitert IFoo.

Wenn Sie .NET 3.5, die einfachste Art und Weise zu umgehen dies in Ihrem Fall verwendet, ist die DirectCast zu entfernen und stattdessen Enumerable.Cast:

Dosomethingelse(dos.Cast(Of SharedLibrary.IAddinSettings)) 
+0

Danke, wenn Sie die einfachste Art und Weise erwähnen, gibt es noch einer? Ich habe schon etwas über enumerable.cast gelesen und der Rat war, dies zu vermeiden (Laufzeitkonvertierung?) – Johan

+0

Die Konvertierung * muss * eine Laufzeit sein, wegen der Inkompatibilität der beiden Listentypen. Jemand * könnte * eine Implementierung von IExecuteDoSomething hinzugefügt haben, die IAddinSettings nicht implementiert. –

+0

Vielen Dank, scheint mit der Besetzung zu arbeiten, kann jetzt weiter programmieren ... – Johan