JeeShen Lee
JeeShen Lee

Reputation: 3816

MEF with open generic type

I have these interfaces

public interface IImageSource<T>
{
    // Properties
    T OutputFrame { get; set; }
    string Name { get; set; }
    Guid Guid { get; set; }

    // Events
    event EventHandler<DmEventArgs<T>> NewFrameOutput;

    // Methods
    bool Start();
    bool Stop();
    void Initialize();
}

public interface IImageFilter<TIn, TOut>
{
    // Properties
    TIn Input { get; set; }
    string Name { get; set; }
    Guid Guid { get; set; }

    TOut Process(TIn frame);
}

Based on these interfaces i created classes like

[Export(typeof(IImageSource<>))]
public class AForgeImageSource : IImageSource<Image<Bgr, byte>>
{
    // Implementation...
}

[Export(typeof(IImageFilter<,>))]
public class AnotherFilter1 : IImageFilter<Image<Bgr, byte>, Image<Bgr, byte>>
{
    // Implementation...
}

The question is how do i use MEF to fufill all the object that implement IImageSource into an observable collection ImageSources? or how to use MEF to get all the object that implement IImageFilter into an observable collection ImageFilters?

I tried the below but not working. BTW, i'm using MEF and MEF Contrib.

    [ImportMany]
    public ObservableCollection<IImageSource<object>> ImageSources
    {
        // Implementation...
    }

    [ImportMany(typeof(IImageFilter<object, object>))]
    public ObservableCollection<IImageFilter<object, object>> ImageFilters
    {
        // Implementation...
    }

The collection of the ImageFilters can be make up of

IImageFilter<string, string>
IImageFilter<string, int>
IImageFilter<int, double>

and here's the code I get MEF to do the composition.

public void LoadPluginList()
{
    var pluginsDirectoryPath = Environment.CurrentDirectory + "\\Plugins";
    //var aggregateCatalog = new AggregateCatalog();
    //var genericCatalog = new GenericCatalog();

    var catalog = new DirectoryCatalog(pluginsDirectoryPath);
    var container = new CompositionContainer(catalog);

    container.ComposeParts(this);
}

Any idea how to get this to work?

Upvotes: 3

Views: 4151

Answers (2)

Gusdor
Gusdor

Reputation: 14334

Here are some samples

These do not work

Cardinality mistmatch results in TestModule being rejected.

1.

[Export(typeof(IEnumerable<>))]
public class IntegerCollection: List<int>
{

}

[ModuleExport(typeof(TestModule))]
public class TestModule : Microsoft.Practices.Prism.Modularity.IModule
{
    [Import(typeof(IEnumerable<>))]
    public IEnumerable<int> Integers
    {
        get { return m_Integers; }
        set { m_Integers = value; }
    } private IEnumerable<int> m_Integers;


    public void Initialize()
    {
    }
}

2.

[Export(typeof(IEnumerable<>))]
public class IntegerCollection: List<int>
{

}

[ModuleExport(typeof(TestModule))]
public class TestModule : Microsoft.Practices.Prism.Modularity.IModule
{
    [Import]
    public IEnumerable<int> Integers
    {
        get { return m_Integers; }
        set { m_Integers = value; }
    } private IEnumerable<int> m_Integers;


    public void Initialize()
    {
    }
}

This one works

[Export(typeof(IEnumerable<object>))]
public class IntegerCollection: List<int>
{

}

[ModuleExport(typeof(TestModule))]
public class TestModule : Microsoft.Practices.Prism.Modularity.IModule
{
    [Import(typeof(IEnumerable<object>))]
    public IEnumerable<int> Integers
    {
        get { return m_Integers; }
        set { m_Integers = value; }
    } private IEnumerable<int> m_Integers;


    public void Initialize()
    {
    }
}

Why? Well, int is assignable from object, so i can export IEnumerable<int> as IEnumerable<object> with no problem.

However, if i exported an IEnumerable<double> and IEnumerable<object> instead, it will fail because double is not assignable to int.

My recommendations:

  • Consider a non-generic base interface
  • Import your filters to a property of type IEnumerable but use a contract name string to for the exports and import definitions. e.g. [Export("IMAGE_FILTERS")]

Upvotes: 2

Hiệp L&#234;
Hiệp L&#234;

Reputation: 634

The export and import type does not match. Try

[Export(typeof(IImageFilter<object,object>))]
public class AnotherFilter1 : IImageFilter<Image<Bgr, byte>, Image<Bgr, byte>>
{
// Implementation...
}

Upvotes: 0

Related Questions