1 // -----------------------------------------------------------------------
\r
2 // Copyright (c) Microsoft Corporation. All rights reserved.
\r
3 // -----------------------------------------------------------------------
\r
5 using System.Collections.Generic;
\r
6 using System.ComponentModel.Composition.Primitives;
\r
7 using System.Globalization;
\r
9 using System.Linq.Expressions;
\r
10 using System.Threading;
\r
11 using Microsoft.Internal;
\r
13 namespace System.ComponentModel.Composition.Hosting
\r
16 /// A mutable collection of <see cref="ComposablePartCatalog"/>s.
\r
19 /// This type is thread safe.
\r
21 public class AggregateCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged
\r
23 private ComposablePartCatalogCollection _catalogs = null;
\r
24 private volatile int _isDisposed = 0;
\r
25 private IQueryable<ComposablePartDefinition> _partsQuery;
\r
28 /// Initializes a new instance of the <see cref="AggregateCatalog"/> class.
\r
30 public AggregateCatalog()
\r
31 : this((IEnumerable<ComposablePartCatalog>)null)
\r
36 /// Initializes a new instance of the <see cref="AggregateCatalog"/> class
\r
37 /// with the specified catalogs.
\r
39 /// <param name="catalogs">
\r
40 /// An <see cref="Array"/> of <see cref="ComposablePartCatalog"/> objects to add to the
\r
41 /// <see cref="AggregateCatalog"/>.
\r
43 /// <exception cref="ArgumentNullException">
\r
44 /// <paramref name="catalogs"/> is <see langword="null"/>.
\r
46 /// <exception cref="ArgumentException">
\r
47 /// <paramref name="catalogs"/> contains an element that is <see langword="null"/>.
\r
49 public AggregateCatalog(params ComposablePartCatalog[] catalogs)
\r
50 : this((IEnumerable<ComposablePartCatalog>)catalogs)
\r
55 /// Initializes a new instance of the <see cref="AggregateCatalog"/> class
\r
56 /// with the specified catalogs.
\r
58 /// <param name="catalogs">
\r
59 /// An <see cref="IEnumerable{T}"/> of <see cref="ComposablePartCatalog"/> objects to add
\r
60 /// to the <see cref="AggregateCatalog"/>; or <see langword="null"/> to
\r
61 /// create an <see cref="AggregateCatalog"/> that is empty.
\r
63 /// <exception cref="ArgumentException">
\r
64 /// <paramref name="catalogs"/> contains an element that is <see langword="null"/>.
\r
66 public AggregateCatalog(IEnumerable<ComposablePartCatalog> catalogs)
\r
68 Requires.NullOrNotNullElements(catalogs, "catalogs");
\r
70 this._catalogs = new ComposablePartCatalogCollection(catalogs, this.OnChanged, this.OnChanging);
\r
71 this._partsQuery = this._catalogs.AsQueryable().SelectMany(catalog => catalog.Parts);
\r
75 /// Notify when the contents of the Catalog has changed.
\r
77 public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed
\r
81 this._catalogs.Changed += value;
\r
85 this._catalogs.Changed -= value;
\r
90 /// Notify when the contents of the Catalog has changing.
\r
92 public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing
\r
96 this._catalogs.Changing += value;
\r
100 this._catalogs.Changing -= value;
\r
105 /// Gets the part definitions of the catalog.
\r
108 /// A <see cref="IQueryable{T}"/> of <see cref="ComposablePartDefinition"/> objects of the
\r
109 /// <see cref="AggregateCatalog"/>.
\r
111 /// <exception cref="ObjectDisposedException">
\r
112 /// The <see cref="AggregateCatalog"/> has been disposed of.
\r
114 public override IQueryable<ComposablePartDefinition> Parts
\r
118 this.ThrowIfDisposed();
\r
119 return this._partsQuery;
\r
124 /// Returns the export definitions that match the constraint defined by the specified definition.
\r
126 /// <param name="definition">
\r
127 /// The <see cref="ImportDefinition"/> that defines the conditions of the
\r
128 /// <see cref="ExportDefinition"/> objects to return.
\r
131 /// An <see cref="IEnumerable{T}"/> of <see cref="Tuple{T1, T2}"/> containing the
\r
132 /// <see cref="ExportDefinition"/> objects and their associated
\r
133 /// <see cref="ComposablePartDefinition"/> for objects that match the constraint defined
\r
134 /// by <paramref name="definition"/>.
\r
136 /// <exception cref="ArgumentNullException">
\r
137 /// <paramref name="definition"/> is <see langword="null"/>.
\r
139 /// <exception cref="ObjectDisposedException">
\r
140 /// The <see cref="AggregateCatalog"/> has been disposed of.
\r
142 public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition)
\r
144 this.ThrowIfDisposed();
\r
146 Requires.NotNull(definition, "definition");
\r
148 // delegate the query to each catalog and merge the results.
\r
149 var exports = new List<Tuple<ComposablePartDefinition, ExportDefinition>>();
\r
150 foreach (var catalog in this._catalogs)
\r
152 foreach (var export in catalog.GetExports(definition))
\r
154 exports.Add(export);
\r
161 /// Gets the underlying catalogs of the catalog.
\r
164 /// An <see cref="ICollection{T}"/> of underlying <see cref="ComposablePartCatalog"/> objects
\r
165 /// of the <see cref="AggregateCatalog"/>.
\r
167 /// <exception cref="ObjectDisposedException">
\r
168 /// The <see cref="AggregateCatalog"/> has been disposed of.
\r
170 public ICollection<ComposablePartCatalog> Catalogs
\r
174 this.ThrowIfDisposed();
\r
175 return this._catalogs;
\r
179 protected override void Dispose(bool disposing)
\r
185 // NOTE : According to http://msdn.microsoft.com/en-us/library/4bw5ewxy.aspx, the warning is bogus when used with Interlocked API.
\r
186 #pragma warning disable 420
\r
187 if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0)
\r
188 #pragma warning restore 420
\r
190 this._catalogs.Dispose();
\r
196 base.Dispose(disposing);
\r
201 /// Raises the <see cref="INotifyComposablePartCatalogChanged.Changed"/> event.
\r
203 /// <param name="e">
\r
204 /// An <see cref="ComposablePartCatalogChangeEventArgs"/> containing the data for the event.
\r
206 protected virtual void OnChanged(ComposablePartCatalogChangeEventArgs e)
\r
208 this._catalogs.OnChanged(this, e);
\r
212 /// Raises the <see cref="INotifyComposablePartCatalogChanged.Changing"/> event.
\r
214 /// <param name="e">
\r
215 /// An <see cref="ComposablePartCatalogChangeEventArgs"/> containing the data for the event.
\r
217 protected virtual void OnChanging(ComposablePartCatalogChangeEventArgs e)
\r
219 this._catalogs.OnChanging(this, e);
\r
222 private void ThrowIfDisposed()
\r
224 if (this._isDisposed == 1)
\r
226 throw ExceptionBuilder.CreateObjectDisposed(this);
\r