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