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