`

How-to:应用mef 提高程序扩展能力(part2)

阅读更多

More Value of MEF

一、catalog基本使用

Ok, I think we can all agree that we added a little complexity if all we were going to do is factor what was in the same assembly. MEF really shines when you have separate independent groups working on different components.  By definition these are often in different assemblies with cross no dependencies.  To show how MEF supports this, let's add a new Class Library project to our solution.    Call it ExternalMessages and add a reference to the System.ComponentModel.Composition.dll assembly.

 

STEP 1:

Add the following class.

   1: using System;
   2: using System.ComponentModel.Composition;
   3:  
   4: public class Class1
   5: {
   6:     [Export]
   7:     public string Message
   8:     {
   9:         get
  10:         {
  11:             return "I am starting to get it...";
  12:         }
  13:     }
  14: }

 

STEP 2:

Now we need to wire up this class into the catalog...    Notice in line 6, we change the catalog to look in a directory for the parts... 

 

   1: public void Run()
   2:  {
   3:      //SimpleHello hello = new SimpleHello();
   4:      //Message = hello.Message;
   5:      var catalog = new DirectoryPartCatalog(@"..\..\..\ExternalMessages\bin\Debug");
   6:          // new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
   7:      var container = new CompositionContainer(catalog.CreateResolver());
   8:      container.AddPart(this);
   9:      container.Compose();
  10:  
  11:      foreach (var s in Messages)
  12:      {
  13:          Console.WriteLine(s);
  14:      }
  15:  
  16:  
  17:      Console.ReadKey();
  18:  }

Note: DirectoryPartCatalog also supports relative paths that will look for a path under the current AppDomain.CurrentDomain.BaseDirectory.  For example:
new DirectoryPartCatalog(@”.\extensions\”);

Run it and we get our new message! 

 

STEP 3:

Cool, but we lost our old messages, and I kind of liked them too...  Well, luckily, we have an aggregate part catalog that can take parts from several sources.

   1: public void Run()
   2:  {
   3:      //SimpleHello hello = new SimpleHello();
   4:      //Message = hello.Message;
   5:      var catalog = new AggregatingComposablePartCatalog();
   6:         catalog.Catalogs.Add (new DirectoryPartCatalog(@"..\..\..\ExternalMessages\bin\Debug"));
   7:         catalog.Catalogs.Add (new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));
   8:      var container = new CompositionContainer(catalog.CreateResolver());
   9:      container.AddPart(this);
  10:      container.Compose();

Pretty cool, we now get all the messages!

 

输出为:

I am starting to get it ...

hello world!!

This is getting fun!

 

STEP 4:

Finally, just to bring up the point here... I created a bunch of different assemblies that exported Messages... All I need to do is point the catalog at them and go. 



 

   1: public void Run()
   2: {
   3:     //SimpleHello hello = new SimpleHello();
   4:     //Message = hello.Message;
   5:     var catalog = new AggregatingComposablePartCatalog();
   6:        catalog.Catalogs.Add (new DirectoryPartCatalog(@"..\..\..\ExternalMessages\bin\Debug"));
   7:        catalog.Catalogs.Add(new DirectoryPartCatalog(@"..\..\..\ExtraMessages"));
   8:        catalog.Catalogs.Add (new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));
   9:     var container = new CompositionContainer(catalog.CreateResolver());
  10:     container.AddPart(this);
  11:     container.Compose();
  12:  

See where I added them in line 7..    Now just copy the assemblies into this directory and they become available for this program to use! Notice how I don't need to change any of the logic of the core program as I add more and more extensions. 

 

输出看下图:



 

Taking MEF to the Next Level

Above I showed the simplest scenario... let's get a bit more powerful.  If you pick apart the main program looking for tight coupling, that Console.WriteLine() will really stand out.. What if you want to log to a file, call a web service or print to HTML or WPF?   Tightly coupling to the Console does not make that easy.  How can we use the seperation of concerns principle and MEF to get rid of this tight coupling? 

 

二、进行一点点扩展

STEP 1:

First, we need to define an interface that describes the contract for outputting strings.  To ensure correct dependency management go ahead and create a new Library project called SharedLibrary, add this interface and reference this project from each of the other team projects. 

   1: namespace SharedLibrary
   2: {
   3:     public interface IOutputString
   4:     {
   5:         void OutputStringToConsole(string value);
   6:     }
   7: }

 

STEP 2:

Now, back in the main program we can factor out the Console.WriteLine ()...

   1: class Program
   2: {
   3:     [Import]
   4:     public IEnumerable<string> Messages { get; set; }
   5:  
   6:     [Import]
   7:     public IOutputString Out { get; set; }
   8:  
   9:     public void Run()
  10:     {
  11:         //SimpleHello hello = new SimpleHello();
  12:         //Message = hello.Message;
  13:         var catalog = new AggregatingComposablePartCatalog();
  14:            catalog.Catalogs.Add (new DirectoryPartCatalog(@"..\..\..\ExternalMessages\bin\Debug"));
  15:            catalog.Catalogs.Add(new DirectoryPartCatalog(@"..\..\..\ExtraMessages"));
  16:            catalog.Catalogs.Add (new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly()));
  17:         var container = new CompositionContainer(catalog.CreateResolver());
  18:         container.AddPart(this);
  19:         container.Compose();
  20:  
  21:         foreach (var s in Messages)
  22:         {
  23:             Out.OutputString(s);
  24:         }
  25:  
  26:     
  27:         Console.ReadKey();
  28:     }

In line 6-7 we define Out and in line 23 we change from Console.WriteLine() to Out.OutputString().

 

STEP 3:

Now in External Messages project add the following class

   1: [Export(typeof(IOutputString))]
   2: public class Class1 : IOutputString
   3: {
   4:     public void OutputString(string value)
   5:     {
   6:         Console.WriteLine("Output=" + value);
   7:     }
   8:  
   9:     

 

Notice here we are explicitly saying the expert type to be that shared interface.  Now when we run it we get:



 

  • 大小: 129.1 KB
  • 大小: 73.5 KB
  • 大小: 63.2 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics