views:

200

answers:

1

I have the following problem with MEF:

Interface definition to be used by host:

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

extra interface needed by some other code inside the host:

 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

The class that provides the export:

 <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

The host:

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

Everything seems to work fine until the Button2_Click routine is executed, then an InvalidCastException is thrown with the info:
Unable to cast object of type 'System.Collections.Generic.List1[SharedLibrary.IExecuteDoSomething]' to type 'System.Collections.Generic.List1[SharedLibrary.IAddinSettings]'.

How can i solve this problem, because the imported object implements both of the interfaces?

A: 

I suspect you're actually running into a covariance issue - that's the typical cause of problems like this. A List<IFoo> is not a List<IBar> even if IBar extends IFoo.

If you're using .NET 3.5, the easiest way to get round this in your case is to remove the DirectCast and instead use Enumerable.Cast:

Dosomethingelse(dos.Cast(Of SharedLibrary.IAddinSettings))
Jon Skeet
Thanks, if you mention the easiest way, is there another one? I have already read something about enumerable.cast and the advice was to avoid this (runtime convertion?)
Johan
The conversion *has* to be a runtime one, because of the incompatibility of the two list types. Someone *could* have added an implementation of IExecuteDoSomething which doesn't implement IAddinSettings.
Jon Skeet
Thank you very much, seems to work with the cast, can continue coding now ...
Johan