// ----------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. // ----------------------------------------------------------------------- using System; using System.Collections.Generic; using System.ComponentModel.Composition.Primitives; using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Threading; using Microsoft.Internal; namespace System.ComponentModel.Composition.Hosting { /// /// A mutable collection of s. /// /// /// This type is thread safe. /// public class AggregateCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged { private ComposablePartCatalogCollection _catalogs = null; private volatile int _isDisposed = 0; private IQueryable _partsQuery; /// /// Initializes a new instance of the class. /// public AggregateCatalog() : this((IEnumerable)null) { } /// /// Initializes a new instance of the class /// with the specified catalogs. /// /// /// An of objects to add to the /// . /// /// /// is . /// /// /// contains an element that is . /// public AggregateCatalog(params ComposablePartCatalog[] catalogs) : this((IEnumerable)catalogs) { } /// /// Initializes a new instance of the class /// with the specified catalogs. /// /// /// An of objects to add /// to the ; or to /// create an that is empty. /// /// /// contains an element that is . /// public AggregateCatalog(IEnumerable catalogs) { Requires.NullOrNotNullElements(catalogs, "catalogs"); this._catalogs = new ComposablePartCatalogCollection(catalogs, this.OnChanged, this.OnChanging); this._partsQuery = this._catalogs.AsQueryable().SelectMany(catalog => catalog.Parts); } /// /// Notify when the contents of the Catalog has changed. /// public event EventHandler Changed { add { this._catalogs.Changed += value; } remove { this._catalogs.Changed -= value; } } /// /// Notify when the contents of the Catalog has changing. /// public event EventHandler Changing { add { this._catalogs.Changing += value; } remove { this._catalogs.Changing -= value; } } /// /// Gets the part definitions of the catalog. /// /// /// A of objects of the /// . /// /// /// The has been disposed of. /// public override IQueryable Parts { get { this.ThrowIfDisposed(); return this._partsQuery; } } /// /// Returns the export definitions that match the constraint defined by the specified definition. /// /// /// The that defines the conditions of the /// objects to return. /// /// /// An of containing the /// objects and their associated /// for objects that match the constraint defined /// by . /// /// /// is . /// /// /// The has been disposed of. /// public override IEnumerable> GetExports(ImportDefinition definition) { this.ThrowIfDisposed(); Requires.NotNull(definition, "definition"); // delegate the query to each catalog and merge the results. var exports = new List>(); foreach (var catalog in this._catalogs) { foreach (var export in catalog.GetExports(definition)) { exports.Add(export); } } return exports; } /// /// Gets the underlying catalogs of the catalog. /// /// /// An of underlying objects /// of the . /// /// /// The has been disposed of. /// public ICollection Catalogs { get { this.ThrowIfDisposed(); return this._catalogs; } } protected override void Dispose(bool disposing) { try { if (disposing) { // NOTE : According to http://msdn.microsoft.com/en-us/library/4bw5ewxy.aspx, the warning is bogus when used with Interlocked API. #pragma warning disable 420 if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0) #pragma warning restore 420 { this._catalogs.Dispose(); } } } finally { base.Dispose(disposing); } } /// /// Raises the event. /// /// /// An containing the data for the event. /// protected virtual void OnChanged(ComposablePartCatalogChangeEventArgs e) { this._catalogs.OnChanged(this, e); } /// /// Raises the event. /// /// /// An containing the data for the event. /// protected virtual void OnChanging(ComposablePartCatalogChangeEventArgs e) { this._catalogs.OnChanging(this, e); } private void ThrowIfDisposed() { if (this._isDisposed == 1) { throw ExceptionBuilder.CreateObjectDisposed(this); } } } }