第二章 【C#进阶系列】【MEF框架(二)】
第一章 【C#进阶系列】【MEF框架(一)】
在(一)已经对MEF作了基本的介绍,这里针对MEF的导出[Export]和导入[Import]作一些补充。
在接口上面写注解,这样只要实现了这个接口的类都会导出,而不需要在每个类上面都写注解
如下代码,在接口中添加[InheritedExport]特性,实现类的Export已经注释掉了,最终效果仍然一样。
注意:这种方法虽然比较简单,但是只适用于比较简单的应用
namespace MEF_P1
{
[InheritedExport]
public interface IBookService
{
string GetBookName();
}
//[Export(typeof(IBookService))]
public class MathBook : IBookService
{
public string GetBookName()
{
return "MathBook";
}
}
class Program
{
[Import]
public IBookService Service { get; set; }
static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
if (pro.Service != null)
{
Console.WriteLine(pro.Service.GetBookName());
}
Console.Read();
}
private void Compose()
{
//创建一个程序集目录,用于从一个程序集获取所有的组件定义
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
//创建容器
CompositionContainer container = new CompositionContainer(catalog);
//组合部件:如果该类有Import,就会自动去寻找Export
container.ComposeParts(this);
}
}
}
直接看下面代码示例:
namespace MEF_P1
{
public interface IBookService
{
string GetBookName();
}
[Export(typeof(IBookService))]
public class MathBook : IBookService
{
public string GetBookName()
{
return "MathBook";
}
}
class Program
{
[Import]
public IBookService Service { get; set; }
static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
if (pro.Service != null)
{
Console.WriteLine(pro.Service.GetBookName());
}
Console.Read();
}
private void Compose()
{
//创建一个程序集目录,用于从一个程序集获取所有的组件定义
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
//创建容器
CompositionContainer container = new CompositionContainer(catalog);
//组合部件:如果该类有Import,就会自动去寻找Export
container.ComposeParts(this);
}
}
}
如果存在多个Export,那就要使用[ImportMany]来代替[Import],再使用for循环逐个输出:
namespace MEF_P1
{
public interface IBookService
{
string GetBookName();
}
[Export(typeof(IBookService))]
public class MathBook : IBookService
{
public string GetBookName()
{
return "MathBook";
}
}
[Export(typeof(IBookService))]
public class ChineseBook : IBookService
{
public string GetBookName()
{
return "ChineseBook";
}
}
class Program
{
[ImportMany]
public IEnumerable<IBookService> Services { get; set; }
static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
foreach (IBookService service in pro.Services)
{
Console.WriteLine(service.GetBookName());
}
Console.Read();
}
private void Compose()
{
//创建一个程序集目录,用于从一个程序集获取所有的组件定义
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
//创建容器
CompositionContainer container = new CompositionContainer(catalog);
//组合部件:如果该类有Import,就会自动去寻找Export
container.ComposeParts(this);
}
}
}
[Export(“ContractName”,typeof(InterfaceName))]
多出了一个参数,其实就是契约名,理论上名字可以随便起,而且可以重复,但是如果名字乱起,和其他DLL中的契约名重复,会导致程序出现很多BUG,所以这个名字一定要按照一定的规范命名。
有了契约名之后,导入[Import]时就要指定契约名,否则无法找到Export了
namespace MEF_P1
{
public interface IBookService
{
string GetBookName();
}
[Export("ContractName_MathBook", typeof(IBookService))]
public class MathBook : IBookService
{
public string GetBookName()
{
return "MathBook";
}
}
[Export("ContractName_ChineseBook", typeof(IBookService))]
public class ChineseBook : IBookService
{
public string GetBookName()
{
return "ChineseBook";
}
}
class Program
{
[Import("ContractName_MathBook")]
public IBookService Services_MathBook { get; set; }
[Import("ContractName_ChineseBook")]
public IBookService Services_ChineseBook { get; set; }
static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
if (pro.Services_MathBook != null)
{
Console.WriteLine(pro.Services_MathBook.GetBookName());
}
if (pro.Services_ChineseBook != null)
{
Console.WriteLine(pro.Services_ChineseBook.GetBookName());
}
Console.Read();
}
private void Compose()
{
//创建一个程序集目录,用于从一个程序集获取所有的组件定义
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
//创建容器
CompositionContainer container = new CompositionContainer(catalog);
//组合部件:如果该类有Import,就会自动去寻找Export
container.ComposeParts(this);
}
}
}
获取Export的方式
可以用过Import+container.ComposeParts(this)方式
也可以直接使用container.GetExportedValue(ContractName);方式
namespace MEF_P1
{
public interface IBookService
{
string GetBookName();
}
[Export("ContractName_MathBook")]
public class MathBook : IBookService
{
public string GetBookName()
{
return "MathBook";
}
}
[Export("ContractName_ChineseBook")]
public class ChineseBook : IBookService
{
public string GetBookName()
{
return "ChineseBook";
}
}
class Program
{
public object Services_MathBook { get; set; }
public object Services_ChineseBook { get; set; }
static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
if (pro.Services_MathBook != null)
{
Console.WriteLine(((IBookService)pro.Services_MathBook).GetBookName());
}
if (pro.Services_ChineseBook != null)
{
Console.WriteLine(((IBookService)pro.Services_ChineseBook).GetBookName());
}
Console.Read();
}
private void Compose()
{
//创建一个程序集目录,用于从一个程序集获取所有的组件定义
AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
//创建容器
CompositionContainer container = new CompositionContainer(catalog);
//直接通过契约名获取Export
Services_MathBook = container.GetExportedValue<object>("ContractName_MathBook");
Services_ChineseBook = container.GetExportedValue<object>("ContractName_ChineseBook");
}
}
}
依赖倒置原则:高层模板不应该依赖于底层模板,两者应该依赖于抽象,而抽象不应该依赖于细节。