Fix bugs in sizing TableLayoutPanel (Xamarin bug 18638)
[mono.git] / mcs / class / System.ComponentModel.Composition / src / ComponentModel / System / ComponentModel / Composition / Hosting / AssemblyCatalog.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.ComponentModel.Composition.ReflectionModel;\r
8 using System.Diagnostics;\r
9 using System.Diagnostics.CodeAnalysis;\r
10 using System.Globalization;\r
11 using System.IO;\r
12 using System.Linq;\r
13 using System.Reflection;\r
14 using System.Security;\r
15 using System.Threading;\r
16 using Microsoft.Internal;\r
17 \r
18 namespace System.ComponentModel.Composition.Hosting\r
19 {\r
20     /// <summary>\r
21     ///     An immutable ComposablePartCatalog created from a managed code assembly.\r
22     /// </summary>\r
23     /// <remarks>\r
24     ///     This type is thread safe.\r
25     /// </remarks>\r
26     [DebuggerTypeProxy(typeof(AssemblyCatalogDebuggerProxy))]\r
27     public class AssemblyCatalog : ComposablePartCatalog, ICompositionElement\r
28     {\r
29         private readonly object _thisLock = new object();\r
30         private readonly ICompositionElement _definitionOrigin;\r
31         private volatile Assembly _assembly = null;\r
32         private volatile TypeCatalog _innerCatalog = null;\r
33         private int _isDisposed = 0;\r
34 \r
35 #if !SILVERLIGHT\r
36 \r
37         /// <summary>\r
38         ///     Initializes a new instance of the <see cref="AssemblyCatalog"/> class \r
39         ///     with the specified code base.\r
40         /// </summary>\r
41         /// <param name="codeBase">\r
42         ///     A <see cref="String"/> containing the code base of the assembly containing the\r
43         ///     attributed <see cref="Type"/> objects to add to the <see cref="AssemblyCatalog"/>.\r
44         /// </param>\r
45         /// <exception cref="ArgumentNullException">\r
46         ///     <paramref name="codeBase"/> is <see langword="null"/>.\r
47         /// </exception>\r
48         /// <exception cref="ArgumentException">\r
49         ///     <paramref name="codeBase"/> is a zero-length string, contains only white space, \r
50         ///     or contains one or more invalid characters as defined by <see cref="Path.InvalidPathChars"/>.\r
51         /// </exception>\r
52         /// <exception cref="PathTooLongException">\r
53         ///     The specified path, file name, or both exceed the system-defined maximum length. \r
54         /// </exception>\r
55         /// <exception cref="SecurityException">\r
56         ///     The caller does not have path discovery permission. \r
57         /// </exception>\r
58         /// <exception cref="FileNotFoundException">\r
59         ///     <paramref name="codeBase"/> is not found.\r
60         /// </exception>\r
61         /// <exception cref="FileLoadException ">\r
62         ///     <paramref name="codeBase"/> could not be loaded.\r
63         ///     <para>\r
64         ///         -or-\r
65         ///     </para>\r
66         ///     <paramref name="codeBase"/> specified a directory.\r
67         /// </exception>\r
68         /// <exception cref="BadImageFormatException">\r
69         ///     <paramref name="codeBase"/> is not a valid assembly\r
70         ///     -or- \r
71         ///     Version 2.0 or later of the common language runtime is currently loaded \r
72         ///     and <paramref name="codeBase"/> was compiled with a later version. \r
73         /// </exception>\r
74         /// <remarks>\r
75         ///     The assembly referenced by <paramref langword="codeBase"/> is loaded into the Load context.\r
76         /// </remarks>\r
77         public AssemblyCatalog(string codeBase)\r
78             : this(codeBase, (ICompositionElement)null)\r
79         {\r
80         }\r
81 \r
82         internal AssemblyCatalog(string codeBase, ICompositionElement definitionOrigin)\r
83             : this(LoadAssembly(codeBase), definitionOrigin)\r
84         {\r
85         }\r
86 \r
87 #endif\r
88 \r
89         /// <summary>\r
90         ///     Initializes a new instance of the <see cref="AssemblyCatalog"/> class \r
91         ///     with the specified assembly.\r
92         /// </summary>\r
93         /// <param name="assembly">\r
94         ///     The <see cref="Assembly"/> containing the attributed <see cref="Type"/> objects to \r
95         ///     add to the <see cref="AssemblyCatalog"/>.\r
96         /// </param>\r
97         /// <exception cref="ArgumentException">\r
98         ///     <paramref name="assembly"/> is <see langword="null"/>.\r
99         ///     <para>\r
100         ///         -or-\r
101         ///     </para>    \r
102         ///     <paramref name="assembly"/> was loaded in the reflection-only context.\r
103         /// </exception>\r
104         public AssemblyCatalog(Assembly assembly)\r
105             : this(assembly, (ICompositionElement)null)\r
106         {\r
107         }\r
108 \r
109         internal AssemblyCatalog(Assembly assembly, ICompositionElement definitionOrigin)\r
110         {\r
111             Requires.NotNull(assembly, "assembly");\r
112 \r
113 #if !SILVERLIGHT\r
114             if (assembly.ReflectionOnly)\r
115             {\r
116                 throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.Argument_AssemblyReflectionOnly, "assembly"), "assembly");\r
117             }\r
118 #endif\r
119             this._assembly = assembly;\r
120             this._definitionOrigin = definitionOrigin ?? this;\r
121         }\r
122 \r
123         /// <summary>\r
124         ///     Gets the part definitions of the assembly catalog.\r
125         /// </summary>\r
126         /// <value>\r
127         ///     A <see cref="IQueryable{T}"/> of <see cref="ComposablePartDefinition"/> objects of the \r
128         ///     <see cref="AssemblyCatalog"/>.\r
129         /// </value>\r
130         /// <exception cref="ObjectDisposedException">\r
131         ///     The <see cref="AssemblyCatalog"/> has been disposed of.\r
132         /// </exception>\r
133         public override IQueryable<ComposablePartDefinition> Parts\r
134         {\r
135             get\r
136             {\r
137                 return this.InnerCatalog.Parts;\r
138             }\r
139         }\r
140 \r
141         /// <summary>\r
142         ///     Returns the export definitions that match the constraint defined by the specified definition.\r
143         /// </summary>\r
144         /// <param name="definition">\r
145         ///     The <see cref="ImportDefinition"/> that defines the conditions of the \r
146         ///     <see cref="ExportDefinition"/> objects to return.\r
147         /// </param>\r
148         /// <returns>\r
149         ///     An <see cref="IEnumerable{T}"/> of <see cref="Tuple{T1, T2}"/> containing the \r
150         ///     <see cref="ExportDefinition"/> objects and their associated \r
151         ///     <see cref="ComposablePartDefinition"/> for objects that match the constraint defined \r
152         ///     by <paramref name="definition"/>.\r
153         /// </returns>\r
154         /// <exception cref="ArgumentNullException">\r
155         ///     <paramref name="definition"/> is <see langword="null"/>.\r
156         /// </exception>\r
157         /// <exception cref="ObjectDisposedException">\r
158         ///     The <see cref="ComposablePartCatalog"/> has been disposed of.\r
159         /// </exception>\r
160         /// <remarks>\r
161         ///     <note type="inheritinfo">\r
162         ///         Overriders of this property should never return <see langword="null"/>, if no \r
163         ///         <see cref="ExportDefinition"/> match the conditions defined by \r
164         ///         <paramref name="definition"/>, return an empty <see cref="IEnumerable{T}"/>.\r
165         ///     </note>\r
166         /// </remarks>\r
167         public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition)\r
168         {\r
169             return this.InnerCatalog.GetExports(definition);\r
170         }\r
171 \r
172         private TypeCatalog InnerCatalog\r
173         {\r
174             get\r
175             {\r
176                 this.ThrowIfDisposed();\r
177 \r
178                 if (this._innerCatalog == null)\r
179                 {\r
180                     lock (this._thisLock)\r
181                     {\r
182                         if (this._innerCatalog == null)\r
183                         {\r
184                             var catalog = new TypeCatalog(this._assembly.GetTypes(), _definitionOrigin);\r
185                             this._innerCatalog = catalog;\r
186                         }\r
187                     }\r
188                 }\r
189                 return this._innerCatalog;\r
190             }\r
191         }\r
192 \r
193         /// <summary>\r
194         ///     Gets the assembly containing the attributed types contained within the assembly\r
195         ///     catalog.\r
196         /// </summary>\r
197         /// <value>\r
198         ///     The <see cref="Assembly"/> containing the attributed <see cref="Type"/> objects\r
199         ///     contained within the <see cref="AssemblyCatalog"/>.\r
200         /// </value>\r
201         public Assembly Assembly\r
202         {\r
203             get { return this._assembly; }\r
204         }\r
205 \r
206         /// <summary>\r
207         ///     Gets the display name of the assembly catalog.\r
208         /// </summary>\r
209         /// <value>\r
210         ///     A <see cref="String"/> containing a human-readable display name of the <see cref="AssemblyCatalog"/>.\r
211         /// </value>\r
212         [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]\r
213         string ICompositionElement.DisplayName\r
214         {\r
215             get { return this.GetDisplayName(); }\r
216         }\r
217 \r
218         /// <summary>\r
219         ///     Gets the composition element from which the assembly catalog originated.\r
220         /// </summary>\r
221         /// <value>\r
222         ///     This property always returns <see langword="null"/>.\r
223         /// </value>\r
224         [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]\r
225         ICompositionElement ICompositionElement.Origin\r
226         {\r
227             get { return null; }\r
228         }\r
229 \r
230 \r
231         /// <summary>\r
232         ///     Returns a string representation of the assembly catalog.\r
233         /// </summary>\r
234         /// <returns>\r
235         ///     A <see cref="String"/> containing the string representation of the <see cref="AssemblyCatalog"/>.\r
236         /// </returns>\r
237         public override string ToString()\r
238         {\r
239             return this.GetDisplayName();\r
240         }\r
241 \r
242         protected override void Dispose(bool disposing)\r
243         {                \r
244             try\r
245             {\r
246                 if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0)\r
247                 {\r
248                     if (disposing)\r
249                     {\r
250                         if (this._innerCatalog != null)\r
251                         {\r
252                             this._innerCatalog.Dispose();\r
253                         }\r
254                     }\r
255                 }\r
256             }\r
257             finally\r
258             {\r
259                 base.Dispose(disposing);\r
260             }\r
261         }\r
262 \r
263         private void ThrowIfDisposed()\r
264         {\r
265             if (this._isDisposed == 1)\r
266             {\r
267                 throw ExceptionBuilder.CreateObjectDisposed(this);\r
268             }\r
269         }\r
270 \r
271         private string GetDisplayName()\r
272         {\r
273             return string.Format(CultureInfo.CurrentCulture,\r
274                                 "{0} (Assembly=\"{1}\")",   // NOLOC\r
275                                 GetType().Name, \r
276                                 this.Assembly.FullName);\r
277         }\r
278 \r
279 #if !SILVERLIGHT\r
280 \r
281         private static Assembly LoadAssembly(string codeBase)\r
282         {\r
283             Requires.NotNullOrEmpty(codeBase, "codeBase");\r
284 \r
285             AssemblyName assemblyName;\r
286 \r
287             try\r
288             {\r
289                 assemblyName = AssemblyName.GetAssemblyName(codeBase);\r
290             }\r
291             catch (ArgumentException)\r
292             {\r
293                 assemblyName = new AssemblyName();\r
294                 assemblyName.CodeBase = codeBase;\r
295             }\r
296 \r
297             return Assembly.Load(assemblyName);            \r
298         }\r
299 #endif\r
300     }\r
301 }\r