單例模式就是保證在整個應用程序的生命週期中,在任什麼時候刻,被指定的類只有一個實例,併爲客戶程序提供一個獲取該實例的全局訪問點。多線程
通常使用狀況:函數
private static readonly object _lockObj = new object(); private static TargetObject_instance; /// <summary> /// Get 惟一實例 /// </summary> public static TargetObject Instance { get { if (_instance == null) { lock (_lockObj) { if (_instance == null) _instance = new TargetObject(); } } return _instance; } }
這樣就能保證在多線程模式下,只能使用一個實例了。spa
可是這樣子不便於拓展,每次新增一個類就要多加一個單實例,很不方便,因而就想到了原先介紹使用的MEF,把每一個單實例都當作是一個插件使用,標記後,而後初始化的時候,實例化這些實例,放到相對應的容器中。對應用層只提供從容器中撈取的實例。插件
想法了而後就是實踐了:線程
1 定義單實例的Attributecode
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class PartAttribute : Attribute { }
2 單實例中初始化後,可能須要處理的事件,由於單實例做爲插件使用,通常都是使用無參的構造函數,進行反射實例,必然有些屬性沒法正常加載,必需要讀取配置,或者進行其餘處理,因此就要執行單實例類中初始化的事件,這樣就須要單獨標記MethodAttribute了以區分各種方法,所以第二件事定義MethodAttribute。orm
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] public sealed class PartActivationMethodAttribute : Attribute { }
3 定義容器,存放各種單實例。blog
public sealed class PartContainer { internal IDictionary<Type, PartMetadata> PartInformation { get; set; } public void Initialize(IEnumerable<Assembly> partAssemblies) { } public void Activate() { } }
4定義初始化方法,查找已標記PartAttribute的Assembly生命週期
public void Initialize(IEnumerable<Assembly> partAssemblies) { var partInformation = from asm in partAssemblies from type in asm.GetTypes() where type.IsDefined(typeof(PartAttribute), false) select new { Type = type, Metadata = PartMetadata.GetPartMetadata(type) }; PartInformation = partInformation.ToDictionary(p => p.Type, p => p.Metadata); }
5定義激活方法,調用已標記MethodAttribute的Method事件
public void Activate(IPartActivationContext configuration = null) { // 整理能夠激活的插件類型 var activePartsInfomation = new Dictionary<Type, PartMetadata>(); foreach (var partInfo in PartInformation) { var type = partInfo.Key; var metadata = partInfo.Value; if (configuration == null || configuration.IsPartEnabled(type, metadata)) { activePartsInfomation[type] = metadata; } } // 激活插件 ActiveParts.ForEach(p => OperateActivation<PartActivationMethodAttribute>(p)); } private void OperateActivation<OperationType>(object partInstance) { // 根據Attribute找到方法 var methodInfo = partInstance.GetType() .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .Where(m => m.IsDefined(typeof(OperationType), false)) .ToArray(); if (methodInfo.Length == 0) return; if (methodInfo.Length != 1) throw new PartException(string.Format("重複的部件{0}方法", operationName)); var activationMethod = methodInfo[0]; var methodParameters = activationMethod.GetParameters(); if (methodParameters != null && methodParameters.Length != 0) throw new PartException(string.Format("部件{0}方法不該該包含任何參數", operationName)); methodInfo[0].Invoke(partInstance, null); }
而後就能夠在目標實力類中使用了:
[Part] internal class TargetObject : ITargetObject { [PartActivationMethod] private void Initialize() { } }
使用順序:
定義一個PartContainer partContainer
調用partContainer.Initialize(targetObjectAssemblie);
調用partContainer.Activate();
最後就能在partContainer.ActiveParts中獲取本身想要的Targerobject實例了。