Search code examples
c#mef

How can I get a MEF exported value by a class name?


I have a window called MainWindow and a viewmodel called MainWindowViewModel.

I want to look into MEF's container to see if I can find <WindowName>ViewModel.

The code I have is:

CompositionContainer container;

var catalog = new AssemblyCatalog(typeof(App).Assembly);
container = new CompositionContainer(catalog);
container.ComposeParts(this);
container.SatisfyImportsOnce(this);

I saw the method

container.GetExports(Type, Type, String)

but it only allows me to get exports of the first Type parameter. All I have is a string name.

I wanted to do something like

allExports.FirstOrDefault(e => e.GetType().Name.StartsWith(something))

Is there a way I can get an exported value by a string name?


Solution

  • Since allExports is IEnumerable< Lazy< T >> you can't get each exported type without creating the associated value (by calling .Value), and then inspecting value type. And this is not really a good thing to create all values. All you can get is the typeof(T) by analyzing typeof(Lazy< T >), that's all.

    Metadata is the good way to go :

    [MetadataAttribute]
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class ExportViewModelAttribute : ExportAttribute, IViewModelMetadata
    {
        public ExportViewModelAttribute(Type declaredType)
            : base(null, typeof(IViewModel))
        {
            this.DeclaredType = declaredType;
        }
    
        public Type DeclaredType { get; private set; }
    }
    

    with interface as :

    public interface IViewModelMetadata
    {
        Type DeclaredType { get; } 
    }
    

    then you export with :

    [ExportViewModel(typeof(MyViewModel))]
    public class MyViewModel: BaseViewModel, IViewModel 
    {
        [...]
    }
    

    And then retreive it with a where clause on metadata

    IViewModel vm = container.GetExports<IViewModel, IViewModelMetadata>().Where(i => i.Metadata.DeclaredType == typeof(MyViewModel)).Select(i => i.Value).FirstOrDefault();
    

    or with

    i => i.Metadata.DeclaredType.Name == "mysearchedViewModel"