[mcs] Validate more nameof argument expressions
[mono.git] / mcs / class / System.ComponentModel.Composition / src / ComponentModel / System / ComponentModel / Composition / Hosting / AggregateCatalog.cs
1 // -----------------------------------------------------------------------\r
2 // Copyright (c) Microsoft Corporation.  All rights reserved.\r
3 // -----------------------------------------------------------------------\r
4 using System;\r
5 using System.Collections.Generic;\r
6 using System.ComponentModel.Composition.Primitives;\r
7 using System.Globalization;\r
8 using System.Linq;\r
9 using System.Linq.Expressions;\r
10 using System.Threading;\r
11 using Microsoft.Internal;\r
12 \r
13 namespace System.ComponentModel.Composition.Hosting\r
14 {\r
15     /// <summary>\r
16     ///     A mutable collection of <see cref="ComposablePartCatalog"/>s.  \r
17     /// </summary>\r
18     /// <remarks>\r
19     ///     This type is thread safe.\r
20     /// </remarks>\r
21     public class AggregateCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged\r
22     {\r
23         private ComposablePartCatalogCollection _catalogs = null;\r
24         private volatile int _isDisposed = 0;\r
25         private IQueryable<ComposablePartDefinition> _partsQuery;\r
26 \r
27         /// <summary>\r
28         ///     Initializes a new instance of the <see cref="AggregateCatalog"/> class.\r
29         /// </summary>\r
30         public AggregateCatalog()\r
31             : this((IEnumerable<ComposablePartCatalog>)null)\r
32         {\r
33         }\r
34 \r
35         /// <summary>\r
36         ///     Initializes a new instance of the <see cref="AggregateCatalog"/> class \r
37         ///     with the specified catalogs.\r
38         /// </summary>\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
42         /// </param>\r
43         /// <exception cref="ArgumentNullException">\r
44         ///     <paramref name="catalogs"/> is <see langword="null"/>.\r
45         /// </exception>\r
46         /// <exception cref="ArgumentException">\r
47         ///     <paramref name="catalogs"/> contains an element that is <see langword="null"/>.\r
48         /// </exception>\r
49         public AggregateCatalog(params ComposablePartCatalog[] catalogs)\r
50             : this((IEnumerable<ComposablePartCatalog>)catalogs)\r
51         {\r
52         }\r
53 \r
54         /// <summary>\r
55         ///     Initializes a new instance of the <see cref="AggregateCatalog"/> class\r
56         ///     with the specified catalogs.\r
57         /// </summary>\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
62         /// </param>\r
63         /// <exception cref="ArgumentException">\r
64         ///     <paramref name="catalogs"/> contains an element that is <see langword="null"/>.\r
65         /// </exception>\r
66         public AggregateCatalog(IEnumerable<ComposablePartCatalog> catalogs)\r
67         {\r
68             Requires.NullOrNotNullElements(catalogs, "catalogs");\r
69 \r
70             this._catalogs = new ComposablePartCatalogCollection(catalogs, this.OnChanged, this.OnChanging);\r
71             this._partsQuery = this._catalogs.AsQueryable().SelectMany(catalog => catalog.Parts);\r
72         }\r
73 \r
74         /// <summary>\r
75         /// Notify when the contents of the Catalog has changed.\r
76         /// </summary>\r
77         public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed\r
78         {\r
79             add\r
80             {\r
81                 this._catalogs.Changed += value;\r
82             }\r
83             remove\r
84             {\r
85                 this._catalogs.Changed -= value;\r
86             }\r
87         }\r
88 \r
89         /// <summary>\r
90         /// Notify when the contents of the Catalog has changing.\r
91         /// </summary>\r
92         public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing\r
93         {\r
94             add\r
95             {\r
96                 this._catalogs.Changing += value;\r
97             }\r
98             remove\r
99             {\r
100                 this._catalogs.Changing -= value;\r
101             }\r
102         }\r
103 \r
104         /// <summary>\r
105         ///     Gets the part definitions of the catalog.\r
106         /// </summary>\r
107         /// <value>\r
108         ///     A <see cref="IQueryable{T}"/> of <see cref="ComposablePartDefinition"/> objects of the \r
109         ///     <see cref="AggregateCatalog"/>.\r
110         /// </value>\r
111         /// <exception cref="ObjectDisposedException">\r
112         ///     The <see cref="AggregateCatalog"/> has been disposed of.\r
113         /// </exception>\r
114         public override IQueryable<ComposablePartDefinition> Parts\r
115         {\r
116             get\r
117             {\r
118                 this.ThrowIfDisposed();\r
119                 return this._partsQuery;\r
120             }\r
121         }\r
122 \r
123         /// <summary>\r
124         ///     Returns the export definitions that match the constraint defined by the specified definition.\r
125         /// </summary>\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
129         /// </param>\r
130         /// <returns>\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
135         /// </returns>\r
136         /// <exception cref="ArgumentNullException">\r
137         ///     <paramref name="definition"/> is <see langword="null"/>.\r
138         /// </exception>\r
139         /// <exception cref="ObjectDisposedException">\r
140         ///     The <see cref="AggregateCatalog"/> has been disposed of.\r
141         /// </exception>\r
142         public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition)\r
143         {\r
144             this.ThrowIfDisposed();\r
145 \r
146             Requires.NotNull(definition, "definition");\r
147 \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
151             {\r
152                 foreach (var export in catalog.GetExports(definition))\r
153                 {\r
154                     exports.Add(export);\r
155                 }\r
156             }\r
157             return exports;\r
158         }\r
159 \r
160         /// <summary>\r
161         ///     Gets the underlying catalogs of the catalog.\r
162         /// </summary>\r
163         /// <value>\r
164         ///     An <see cref="ICollection{T}"/> of underlying <see cref="ComposablePartCatalog"/> objects\r
165         ///     of the <see cref="AggregateCatalog"/>.\r
166         /// </value>\r
167         /// <exception cref="ObjectDisposedException">\r
168         ///     The <see cref="AggregateCatalog"/> has been disposed of.\r
169         /// </exception>\r
170         public ICollection<ComposablePartCatalog> Catalogs\r
171         {\r
172             get\r
173             {\r
174                 this.ThrowIfDisposed();\r
175                 return this._catalogs;\r
176             }\r
177         }\r
178 \r
179         protected override void Dispose(bool disposing)\r
180         {\r
181             try\r
182             {\r
183                 if (disposing)\r
184                 {\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
189                     {\r
190                         this._catalogs.Dispose();\r
191                     }\r
192                 }\r
193             }\r
194             finally\r
195             {\r
196                 base.Dispose(disposing);\r
197             }\r
198         }\r
199 \r
200         /// <summary>\r
201         ///     Raises the <see cref="INotifyComposablePartCatalogChanged.Changed"/> event.\r
202         /// </summary>\r
203         /// <param name="e">\r
204         ///     An <see cref="ComposablePartCatalogChangeEventArgs"/> containing the data for the event.\r
205         /// </param>\r
206         protected virtual void OnChanged(ComposablePartCatalogChangeEventArgs e)\r
207         {\r
208             this._catalogs.OnChanged(this, e);\r
209         }\r
210 \r
211         /// <summary>\r
212         ///     Raises the <see cref="INotifyComposablePartCatalogChanged.Changing"/> event.\r
213         /// </summary>\r
214         /// <param name="e">\r
215         ///     An <see cref="ComposablePartCatalogChangeEventArgs"/> containing the data for the event.\r
216         /// </param>\r
217         protected virtual void OnChanging(ComposablePartCatalogChangeEventArgs e)\r
218         {\r
219             this._catalogs.OnChanging(this, e);\r
220         }\r
221 \r
222         private void ThrowIfDisposed()\r
223         {\r
224             if (this._isDisposed == 1)\r
225             {\r
226                 throw ExceptionBuilder.CreateObjectDisposed(this);\r
227             }\r
228         }\r
229     }\r
230 }\r