學習Prism一定要掌握依賴注入的應用,只有瞭解了Prism的依賴注入才能更好的使用Prism提升應用開發的架構。
首先說明Prism依賴注入有兩種方式及MEF和Unity ,在Prism中是兩個沒有關聯的dll。我傾向於使用MEF,下面學習下MEF在Silverlight中的具體實現。先看MEF實現圖示
1、Catalog(目錄):爲了發現可用於組合容器的部件,組合容器將使用“Catalog”。目錄是一個對象,通過它發現可用部件,MEF 提供了用於從提供的類型、程序集或磁盤路徑創建Catalog
2、Compose(組合):在MEF中,容器將導入與導出匹配的這一過程我們稱之爲組合,部件由 MEF 組合,MEF 將部件實例化,然後使導出程序與導入程序相匹配。
3、Part(部件):通過 MEF,應用程序可以通過部件的元數據來發現並檢查部件,而不用實例化部件,或者甚至不用加載部件的程序集。在部件中可以指定1個或多個Export和Import。
4、Export(導出):在MEF中通過在類或屬性中添加Export屬性標籤表明該對象能夠被其他部件引入。
5、Import(導入):是通過向Container申請導入滿足條件的對象實例。
在Import時需要遵循Export契約,否則導入將會失敗。
按照MEF的約定,任何一個類或者是接口的實現都可以通過[System.ComponentModel.Composition.Export] 屬性將其他定義組合部件(Composable Parts),在任何需要導入組合部件的地方都可以通過在特定的組合部件對象屬性上使用 [System.ComponentModel.Composition.Import ]實現部件的組合,兩者之間通過契約(Contracts)進行 通信。
在MEF中所有組合都需要匹配契約,契約可以是一個字符串或和類型,每一個Export都需要聲明一個契約,同樣每一個Import都可以定義相同的契約進行匹配。缺省情況下會按照type進行匹配。如果在Export中指定名稱則按名稱進行匹配。強烈推薦使用契約名稱進行匹配,契約名稱可加入命名空間,這樣匹配更加準確方便。
下面看實例,來自http://mef.codeplex.com/
1、對象注入
[Export]
public class SomeComposablePart { ...}
2、屬性注入
public class Configuration
{
[Export("Timeout")]
public int Timeout
{
get { return int.Parse(ConfigurationManager.AppSettings["Timeout"]); }
}
}
[Export]
public class UsesTimeout
{
[Import("Timeout")]
public int Timeout { get; set; }
}
3、方法注入
public class MessageSender
{
[Export(typeof(Action<string>))]
public void Send(string message)
{
Console.WriteLine(message);
}
}
[Export]
public class Processor
{
[Import(typeof(Action<string>))]
public Action<string> MessageSender { get; set; }
public void Send()
{
MessageSender("Processed");
}
}
4、契約可採用字符串進行標註
public class MessageSender
{
[Export("MessageSender")]
public void Send(string message)
{
Console.WriteLine(message);
}
}
[Export]
public class Processor
{
[Import("MessageSender")]
public Action<string> MessageSender { get; set; }
public void Send()
{
MessageSender("Processed");
}
}
5、繼承注入,即在基類或藉口中定義契約,其子類自動應用其契約
[InheritedExport]
public interface ILogger {
void Log(string message);
}
public class Logger : ILogger {
public void Log(string message);
}
6、構造注入
class Program
{
[ImportingConstructor]
public Program(IMessageSender messageSender)
{
...
}
}
7、選項注入
[Export]
public class OrderController {
private ILogger _logger;
[ImportingConstructor]
public OrderController([Import(AllowDefault=true)] ILogger logger) {
if(logger == null)
logger = new DefaultLogger();
_logger = logger;
}
}
8、集合注入
public class Notifier
{
[ImportMany(AllowRecomposition=true)]
public IEnumerable<IMessageSender> Senders {get; set;}
public void Notify(string message)
{
foreach(IMessageSender sender in Senders)
{
sender.Send(message);
}
}
}
9、爲了保障一個對象的某些屬性能夠被及時實例化,可使用IPartImportsSatisfiedNotification
public class Program : IPartImportsSatisfiedNotification
{
[ImportMany]
public IEnumerable<IMessageSender> Senders {get; set;}
public void OnImportsSatisfied()
{
// when this is called, all imports that could be satisfied have been satisfied.
}
}
通過以上介紹基本說明了MEF的注入模式,在實際應用中最重要的也常被忽視的可能就是契約的定義上,如果在類中標示了[Export(typeof(...))]而在引用時使用了[Import["..."]可能會導致無法匹配,另外說明的是所有的部件一定是要被加載到Container中的,否則將會出現無法匹配的異常。