问题
I recognized, that MEF is limited for metro style apps. There is no container anymore, so how can I get specific exported values like ILogger logger = container.GetExportedValues<ILogger>();
?
Is the any tutorial available covering the metro version of MEF?
Thanks for Help, Eny
回答1:
As I already wrote in the comment, I don't really like this approach, but it is the best what I have up to this moment:
public class CompositionContainer
{
private readonly CompositionService _service;
public CompositionContainer(CompositionService service)
{
_service = service;
}
public T GetExportedValue<T>()
{
var factoryProvider = new FactoryProvider<T>();
_service.SatisfyImportsOnce(factoryProvider);
return factoryProvider.Factory.CreateExport().Value;
}
private class FactoryProvider<T>
{
[Import]
public ExportFactory<T> Factory;
}
}
and the simple use-case might be this one:
class Program
{
static void Main()
{
var catalog = new ApplicationCatalog();
var container = new CompositionContainer(catalog.CreateCompositionService());
for (int i = 0; i < 5; i++)
{
var dude = container.GetExportedValue<IDude>();
Console.WriteLine(dude.Say());
}
}
public interface IDude
{
string Say();
}
[Export(typeof(IDude))]
public class Eminem : IDude
{
private static int _instanceNo;
private readonly string _phrase;
public Eminem()
{
_instanceNo++;
_phrase = string.Join(" ", Enumerable.Range(0, _instanceNo)
.Select(_ => "yo!"));
}
public string Say()
{
return _phrase;
}
}
}
I don't care about performance at this moment, but I guess I'll add caching of factory providers or factories later
回答2:
I'm guessing you have discovered the System.CompononentModel.Composition
and System.CompononentModel.Composition.Hosting
namespaces.
Let me give you a simple example here (and see if you are missing anything).
First of all you need a component to inject:
public interface IMefTest
{
string Message {get;}
}
[Export(typeof(IMefTest))]
public class MefTest: IMefTest
{
public string Message {get { return "Hello World"; }}
}
Next you need to set up the CompositionService
(this is similar to a container, but not exactly). We want to set this up somewhere that it can be commonly talked to since this will be where you call to satisfy imports (more on that in code snippet after this one).
I stuck this in the App.xaml.cs in my sample project:
static System.ComponentModel.Composition.ICompositionService _compositionService = null;
public static System.ComponentModel.Composition.ICompositionService CompositionService
{
get
{
if (_compositionService == null)
((App)App.Current).loadCompositionService();
return _compositionService;
}
}
private void loadCompositionService()
{
// Create a catalog where MEF will search for exported parts to plugin
var catalog = new System.ComponentModel.Composition.Hosting.AssemblyCatalog(GetType().GetTypeInfo().Assembly);
_compositionService = catalog.CreateCompositionService();
}
Just a little info on this. We have set up an assembly catalog which means that MEF will interrogate just this Assembly looking for types that are exported. There are other types of catalogs and I believe you should be able to combine 2 or more catalogs together.
Ok, in my page (BTW, I built this into the C# HelloWorld Example from the Getting Started docs on MSDN).
To get an instance of one of the parts in the catalog you simple need to add a property to the class you want to get and add an imports attribute (there are also ways to have it specify arguments on your constructor, but I'm trying to stay simple)
[Import]
public IMefTest Tester { get; set; }
In this example, you'll need to call the composition service's SatisfyImportsOnce method on this class. I did this in the constructor and I did it like this:
if(App.CompositionService != null)
App.CompositionService.SatisfyImportsOnce(this);
(The check to make sure that the service exists is overkill on my part.. it should exist).
After that step you can actually use the Tester.Message
property within your class. There are a lot more options within MEF. I hope this helps you out (and if it does you mark me as the answer as I took valuable time from billing clients to do this for you )
Also, I know you wanted to simply call a container and have it give you back an instance of some type. It is possible to do this with the other forms of MEF, so I imagine it should be able to be done with WinRT, but I am honestly unsure at this time).
来源:https://stackoverflow.com/questions/9522783/how-to-get-exported-values-mef-in-metro-style-apps