f527bef17ace92009bbc5eb00df5221ae3015a07
[platform/upstream/dotnet/runtime.git] /
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3
4 using System.Collections.Generic;
5 using System.Collections.ObjectModel;
6 using System.ComponentModel.Composition.Primitives;
7 using System.Diagnostics.CodeAnalysis;
8 using System.Globalization;
9 using System.Linq;
10 using Microsoft.Internal;
11
12 namespace System.ComponentModel.Composition.Hosting
13 {
14     public abstract partial class ExportProvider
15     {
16         /// <summary>
17         ///     Returns the export with the contract name derived from the specified type parameter,
18         ///     throwing an exception if there is not exactly one matching export.
19         /// </summary>
20         /// <typeparam name="T">
21         ///     The type of the <see cref="Lazy{T}"/> object to return. The contract name is also
22         ///     derived from this type parameter.
23         /// </typeparam>
24         /// <returns>
25         ///     The <see cref="Lazy{T}"/> object with the contract name derived from
26         ///     <typeparamref name="T"/>.
27         /// </returns>
28         /// <remarks>
29         ///     <para>
30         ///         The returned <see cref="Lazy{T}"/> object is an instance of
31         ///         <see cref="Lazy{T, TMetadataView}"/> underneath, where
32         ///         <c>TMetadataView</c>
33         ///         is <see cref="IDictionary{TKey, TValue}"/> and where <c>TKey</c>
34         ///         is <see cref="string"/> and <c>TValue</c> is <see cref="object"/>.
35         ///     </para>
36         ///     <para>
37         ///         The contract name is the result of calling
38         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
39         ///     </para>
40         ///     <para>
41         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
42         ///         using <see cref="StringComparer.Ordinal"/>.
43         ///     </para>
44         /// </remarks>
45         /// <exception cref="ImportCardinalityMismatchException">
46         ///     <para>
47         ///         There are zero <see cref="Lazy{T}"/> objects with the contract name derived
48         ///         from <typeparamref name="T"/> in the <see cref="CompositionContainer"/>.
49         ///     </para>
50         ///     -or-
51         ///     <para>
52         ///         There are more than one <see cref="Lazy{T}"/> objects with the contract name
53         ///         derived from <typeparamref name="T"/> in the <see cref="CompositionContainer"/>.
54         ///     </para>
55         /// </exception>
56         /// <exception cref="ObjectDisposedException">
57         ///     The <see cref="CompositionContainer"/> has been disposed of.
58         /// </exception>
59         public Lazy<T>? GetExport<T>()
60         {
61             return GetExport<T>((string?)null);
62         }
63
64         /// <summary>
65         ///     Returns the export with the specified contract name, throwing an exception if there
66         ///     is not exactly one matching export.
67         /// </summary>
68         /// <typeparam name="T">
69         ///     The type of the <see cref="Lazy{T}"/> object to return.
70         /// </typeparam>
71         /// <param name="contractName">
72         ///     A <see cref="string"/> containing the contract name of the <see cref="Lazy{T}"/>
73         ///     object to return; or <see langword="null"/> or an empty string ("") to use the
74         ///     default contract name.
75         /// </param>
76         /// <returns>
77         ///     The <see cref="Lazy{T}"/> object with the specified contract name.
78         /// </returns>
79         /// <remarks>
80         ///     <para>
81         ///         The returned <see cref="Lazy{T}"/> object is an instance of
82         ///         <see cref="Lazy{T, TMetadataView}"/> underneath, where
83         ///         <c>TMetadataView</c>
84         ///         is <see cref="IDictionary{TKey, TValue}"/> and where <c>TKey</c>
85         ///         is <see cref="string"/> and <c>TValue</c> is <see cref="object"/>.
86         ///     </para>
87         ///     <para>
88         ///         The contract name is the result of calling
89         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
90         ///     </para>
91         ///     <para>
92         ///         The default contract name is compared using a case-sensitive, non-linguistic
93         ///         comparison using <see cref="StringComparer.Ordinal"/>.
94         ///     </para>
95         /// </remarks>
96         /// <exception cref="ImportCardinalityMismatchException">
97         ///     <para>
98         ///         There are zero <see cref="Lazy{T}"/> objects with the specified contract name
99         ///         in the <see cref="CompositionContainer"/>.
100         ///     </para>
101         ///     -or-
102         ///     <para>
103         ///         There are more than one <see cref="Lazy{T}"/> objects with the specified contract
104         ///         name in the <see cref="CompositionContainer"/>.
105         ///     </para>
106         /// </exception>
107         /// <exception cref="ObjectDisposedException">
108         ///     The <see cref="CompositionContainer"/> has been disposed of.
109         /// </exception>
110         public Lazy<T>? GetExport<T>(string? contractName)
111         {
112             return GetExportCore<T>(contractName);
113         }
114
115         /// <summary>
116         ///     Returns the export with the contract name derived from the specified type parameter,
117         ///     throwing an exception if there is not exactly one matching export.
118         /// </summary>
119         /// <typeparam name="T">
120         ///     The type of the <see cref="Lazy{T, TMetadataView}"/> object to return. The
121         ///     contract name is also derived from this type parameter.
122         /// </typeparam>
123         /// <typeparam name="TMetadataView">
124         ///     The type of the metadata view of the <see cref="Lazy{T, TMetadataView}"/> object
125         ///     to return.
126         /// </typeparam>
127         /// <returns>
128         ///     The <see cref="Lazy{T, TMetadataView}"/> object with the contract name derived
129         ///     from <typeparamref name="T"/>.
130         /// </returns>
131         /// <remarks>
132         ///     <para>
133         ///         The contract name is the result of calling
134         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
135         ///     </para>
136         ///     <para>
137         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
138         ///         using <see cref="StringComparer.Ordinal"/>.
139         ///     </para>
140         /// </remarks>
141         /// <exception cref="ImportCardinalityMismatchException">
142         ///     <para>
143         ///         There are zero <see cref="Lazy{T, TMetadataView}"/> objects with the contract
144         ///         name derived from <typeparamref name="T"/> in the
145         ///         <see cref="CompositionContainer"/>.
146         ///     </para>
147         ///     -or-
148         ///     <para>
149         ///         There are more than one <see cref="Lazy{T, TMetadataView}"/> objects with the
150         ///         contract name derived from <typeparamref name="T"/> in the
151         ///         <see cref="CompositionContainer"/>.
152         ///     </para>
153         /// </exception>
154         /// <exception cref="InvalidOperationException">
155         ///     <typeparamref name="TMetadataView"/> is not a valid metadata view type.
156         /// </exception>
157         /// <exception cref="ObjectDisposedException">
158         ///     The <see cref="CompositionContainer"/> has been disposed of.
159         /// </exception>
160         public Lazy<T, TMetadataView>? GetExport<T, TMetadataView>()
161         {
162             return GetExport<T, TMetadataView>((string?)null);
163         }
164
165         /// <summary>
166         ///     Returns the export with the specified contract name, throwing an exception if there
167         ///     is not exactly one matching export.
168         /// </summary>
169         /// <typeparam name="T">
170         ///     The type of the <see cref="Lazy{T, TMetadataView}"/> object to return.
171         /// </typeparam>
172         /// <typeparam name="TMetadataView">
173         ///     The type of the metadata view of the <see cref="Lazy{T, TMetadataView}"/> object
174         ///     to return.
175         /// </typeparam>
176         /// <param name="contractName">
177         ///     A <see cref="string"/> containing the contract name of the
178         ///     <see cref="Lazy{T, TMetadataView}"/> object to return; or <see langword="null"/>
179         ///     or an empty string ("") to use the default contract name.
180         /// </param>
181         /// <returns>
182         ///     The <see cref="Lazy{T, TMetadataView}"/> object with the specified contract name.
183         /// </returns>
184         /// <remarks>
185         ///     <para>
186         ///         The default contract name is the result of calling
187         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
188         ///     </para>
189         ///     <para>
190         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
191         ///         using <see cref="StringComparer.Ordinal"/>.
192         ///     </para>
193         /// </remarks>
194         /// <exception cref="ImportCardinalityMismatchException">
195         ///     <para>
196         ///         There are zero <see cref="Lazy{T, TMetadataView}"/> objects with the
197         ///         specified contract name in the <see cref="CompositionContainer"/>.
198         ///     </para>
199         ///     -or-
200         ///     <para>
201         ///         There are more than one <see cref="Lazy{T, TMetadataView}"/> objects with the
202         ///         specified contract name in the <see cref="CompositionContainer"/>.
203         ///     </para>
204         /// </exception>
205         /// <exception cref="InvalidOperationException">
206         ///     <typeparamref name="TMetadataView"/> is not a valid metadata view type.
207         /// </exception>
208         /// <exception cref="ObjectDisposedException">
209         ///     The <see cref="CompositionContainer"/> has been disposed of.
210         /// </exception>
211         public Lazy<T, TMetadataView>? GetExport<T, TMetadataView>(string? contractName)
212         {
213             return GetExportCore<T, TMetadataView>(contractName);
214         }
215
216         /// <summary>
217         ///     Returns the exports with the specified contract name.
218         /// </summary>
219         /// <param name="type">
220         ///     The <see cref="Type"/> of the <see cref="Export"/> objects to return.
221         /// </param>
222         /// <param name="metadataViewType">
223         ///     The <see cref="Type"/> of the metadata view of the <see cref="Export"/> objects to
224         ///     return.
225         /// </param>
226         /// <param name="contractName">
227         ///     A <see cref="string"/> containing the contract name of the
228         ///     <see cref="Export"/> object to return; or <see langword="null"/>
229         ///     or an empty string ("") to use the default contract name.
230         /// </param>
231         /// <returns>
232         ///     An <see cref="IEnumerable{T}"/> containing the <see cref="Lazy{Object, Object}"/> objects
233         ///     with the specified contract name, if found; otherwise, an empty
234         ///     <see cref="IEnumerable{T}"/>.
235         /// </returns>
236         /// <remarks>
237         ///     <para>
238         ///         The returned <see cref="Export"/> objects are instances of
239         ///         <see cref="Lazy{T, TMetadataView}"/> underneath, where <c>T</c>
240         ///         is <paramref name="type"/> and <c>TMetadataView</c> is
241         ///         <paramref name="metadataViewType"/>.
242         ///     </para>
243         ///     <para>
244         ///         The default contract name is the result of calling
245         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <paramref name="type"/>.
246         ///     </para>
247         ///     <para>
248         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
249         ///         using <see cref="StringComparer.Ordinal"/>.
250         ///     </para>
251         /// </remarks>
252         /// <exception cref="ArgumentNullException">
253         ///     <paramref name="type"/> is <see langword="null"/>.
254         /// </exception>
255         /// <exception cref="InvalidOperationException">
256         ///     <paramref name="metadataViewType"/> is not a valid metadata view type.
257         /// </exception>
258         /// <exception cref="ObjectDisposedException">
259         ///     The <see cref="CompositionContainer"/> has been disposed of.
260         /// </exception>
261         public IEnumerable<Lazy<object, object>> GetExports(Type type, Type? metadataViewType, string? contractName)
262         {
263             IEnumerable<Export> exports = GetExportsCore(type, metadataViewType, contractName, ImportCardinality.ZeroOrMore);
264             Collection<Lazy<object, object>> result = new Collection<Lazy<object, object>>();
265
266             Func<Export, Lazy<object, object>> typedExportFactory = ExportServices.CreateSemiStronglyTypedLazyFactory(type, metadataViewType);
267             foreach (Export export in exports)
268             {
269                 result.Add(typedExportFactory.Invoke(export));
270             }
271
272             return result;
273         }
274
275         /// <summary>
276         ///     Returns the exports with the contract name derived from the specified type parameter.
277         /// </summary>
278         /// <typeparam name="T">
279         ///     The type of the <see cref="Lazy{T}"/> objects to return. The contract name is also
280         ///     derived from this type parameter.
281         /// </typeparam>
282         /// <returns>
283         ///     An <see cref="IEnumerable{T}"/> containing the <see cref="Lazy{T}"/> objects
284         ///     with the contract name derived from <typeparamref name="T"/>, if found; otherwise,
285         ///     an empty <see cref="IEnumerable{T}"/>.
286         /// </returns>
287         /// <remarks>
288         ///     <para>
289         ///         The returned <see cref="Lazy{T}"/> objects are instances of
290         ///         <see cref="Lazy{T, TMetadataView}"/> underneath, where
291         ///         <c>TMetadataView</c>
292         ///         is <see cref="IDictionary{TKey, TValue}"/> and where <c>TKey</c>
293         ///         is <see cref="string"/> and <c>TValue</c> is <see cref="object"/>.
294         ///     </para>
295         ///     <para>
296         ///         The contract name is the result of calling
297         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
298         ///     </para>
299         ///     <para>
300         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
301         ///         using <see cref="StringComparer.Ordinal"/>.
302         ///     </para>
303         /// </remarks>
304         /// <exception cref="ObjectDisposedException">
305         ///     The <see cref="CompositionContainer"/> has been disposed of.
306         /// </exception>
307         public IEnumerable<Lazy<T>> GetExports<T>()
308         {
309             return GetExports<T>((string?)null);
310         }
311
312         /// <summary>
313         ///     Returns the exports with the specified contract name.
314         /// </summary>
315         /// <typeparam name="T">
316         ///     The type of the <see cref="Lazy{T}"/> objects to return.
317         /// </typeparam>
318         /// <param name="contractName">
319         ///     A <see cref="string"/> containing the contract name of the <see cref="Lazy{T}"/>
320         ///     objects to return; or <see langword="null"/> or an empty string ("") to use the
321         ///     default contract name.
322         /// </param>
323         /// <returns>
324         ///     An <see cref="IEnumerable{T}"/> containing the <see cref="Lazy{T}"/> objects
325         ///     with the specified contract name, if found; otherwise, an empty
326         ///     <see cref="IEnumerable{T}"/>.
327         /// </returns>
328         /// <remarks>
329         ///     <para>
330         ///         The returned <see cref="Lazy{T}"/> objects are instances of
331         ///         <see cref="Lazy{T, TMetadataView}"/> underneath, where
332         ///         <c>TMetadataView</c>
333         ///         is <see cref="IDictionary{TKey, TValue}"/> and where <c>TKey</c>
334         ///         is <see cref="string"/> and <c>TValue</c> is <see cref="object"/>.
335         ///     </para>
336         ///     <para>
337         ///         The default contract name is the result of calling
338         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
339         ///     </para>
340         ///     <para>
341         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
342         ///         using <see cref="StringComparer.Ordinal"/>.
343         ///     </para>
344         /// </remarks>
345         /// <exception cref="ObjectDisposedException">
346         ///     The <see cref="CompositionContainer"/> has been disposed of.
347         /// </exception>
348         public IEnumerable<Lazy<T>> GetExports<T>(string? contractName)
349         {
350             return GetExportsCore<T>(contractName);
351         }
352
353         /// <summary>
354         ///     Returns the exports with the contract name derived from the specified type parameter.
355         /// </summary>
356         /// <typeparam name="T">
357         ///     The type of the <see cref="Lazy{T, TMetadataView}"/> objects to return. The
358         ///     contract name is also derived from this type parameter.
359         /// </typeparam>
360         /// <typeparam name="TMetadataView">
361         ///     The type of the metadata view of the <see cref="Lazy{T, TMetadataView}"/> objects
362         ///     to return.
363         /// </typeparam>
364         /// <returns>
365         ///     An <see cref="IEnumerable{T}"/> containing the
366         ///     <see cref="Lazy{T, TMetadataView}"/> objects with the contract name derived from
367         ///     <typeparamref name="T"/>, if found; otherwise, an empty
368         ///     <see cref="IEnumerable{T}"/>.
369         /// </returns>
370         /// <remarks>
371         ///     <para>
372         ///         The contract name is the result of calling
373         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
374         ///     </para>
375         ///     <para>
376         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
377         ///         using <see cref="StringComparer.Ordinal"/>.
378         ///     </para>
379         /// </remarks>
380         /// <exception cref="InvalidOperationException">
381         ///     <typeparamref name="TMetadataView"/> is not a valid metadata view type.
382         /// </exception>
383         /// <exception cref="ObjectDisposedException">
384         ///     The <see cref="CompositionContainer"/> has been disposed of.
385         /// </exception>
386         public IEnumerable<Lazy<T, TMetadataView>> GetExports<T, TMetadataView>()
387         {
388             return GetExports<T, TMetadataView>((string?)null);
389         }
390
391         /// <summary>
392         ///     Returns the exports with the specified contract name.
393         /// </summary>
394         /// <typeparam name="T">
395         ///     The type of the <see cref="Lazy{T, TMetadataView}"/> objects to return. The
396         ///     contract name is also derived from this type parameter.
397         /// </typeparam>
398         /// <typeparam name="TMetadataView">
399         ///     The type of the metadata view of the <see cref="Lazy{T, TMetadataView}"/> objects
400         ///     to return.
401         /// </typeparam>
402         /// <param name="contractName">
403         ///     A <see cref="string"/> containing the contract name of the
404         ///     <see cref="Lazy{T, TMetadataView}"/> objects to return; or <see langword="null"/>
405         ///     or an empty string ("") to use the default contract name.
406         /// </param>
407         /// <returns>
408         ///     An <see cref="IEnumerable{T}"/> containing the
409         ///     <see cref="Lazy{T, TMetadataView}"/> objects with the specified contract name if
410         ///     found; otherwise, an empty <see cref="IEnumerable{T}"/>.
411         /// </returns>
412         /// <remarks>
413         ///     <para>
414         ///         The default contract name is the result of calling
415         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
416         ///     </para>
417         ///     <para>
418         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
419         ///         using <see cref="StringComparer.Ordinal"/>.
420         ///     </para>
421         /// </remarks>
422         /// <exception cref="InvalidOperationException">
423         ///     <typeparamref name="TMetadataView"/> is not a valid metadata view type.
424         /// </exception>
425         /// <exception cref="ObjectDisposedException">
426         ///     The <see cref="CompositionContainer"/> has been disposed of.
427         /// </exception>
428         public IEnumerable<Lazy<T, TMetadataView>> GetExports<T, TMetadataView>(string? contractName)
429         {
430             return GetExportsCore<T, TMetadataView>(contractName);
431         }
432
433         /// <summary>
434         ///     Returns the exported value with the contract name derived from the specified type
435         ///     parameter, throwing an exception if there is not exactly one matching exported value.
436         /// </summary>
437         /// <typeparam name="T">
438         ///     The type of the exported value to return. The contract name is also
439         ///     derived from this type parameter.
440         /// </typeparam>
441         /// <returns>
442         ///     The exported <see cref="object"/> with the contract name derived from
443         ///     <typeparamref name="T"/>.
444         /// </returns>
445         /// <remarks>
446         ///     <para>
447         ///         The contract name is the result of calling
448         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
449         ///     </para>
450         ///     <para>
451         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
452         ///         using <see cref="StringComparer.Ordinal"/>.
453         ///     </para>
454         /// </remarks>
455         /// <exception cref="CompositionContractMismatchException">
456         ///     The underlying exported value cannot be cast to <typeparamref name="T"/>.
457         /// </exception>
458         /// <exception cref="ImportCardinalityMismatchException">
459         ///     <para>
460         ///         There are zero exported values with the contract name derived from
461         ///         <typeparamref name="T"/> in the <see cref="CompositionContainer"/>.
462         ///     </para>
463         ///     -or-
464         ///     <para>
465         ///         There are more than one exported values with the contract name derived from
466         ///         <typeparamref name="T"/> in the <see cref="CompositionContainer"/>.
467         ///     </para>
468         /// </exception>
469         /// <exception cref="ObjectDisposedException">
470         ///     The <see cref="CompositionContainer"/> has been disposed of.
471         /// </exception>
472         /// <exception cref="CompositionException">
473         ///     An error occurred during composition. <see cref="CompositionException.Errors"/> will
474         ///     contain a collection of errors that occurred.
475         /// </exception>
476         public T? GetExportedValue<T>()
477         {
478             return GetExportedValue<T>((string?)null);
479         }
480
481         /// <summary>
482         ///     Returns the exported value with the specified contract name, throwing an exception
483         ///     if there is not exactly one matching exported value.
484         /// </summary>
485         /// <typeparam name="T">
486         ///     The type of the exported value to return.
487         /// </typeparam>
488         /// <param name="contractName">
489         ///     A <see cref="string"/> containing the contract name of the exported value to return,
490         ///     or <see langword="null"/> or an empty string ("") to use the default contract name.
491         /// </param>
492         /// <returns>
493         ///     The exported <see cref="object"/> with the specified contract name.
494         /// </returns>
495         /// <remarks>
496         ///     <para>
497         ///         The default contract name is the result of calling
498         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
499         ///     </para>
500         ///     <para>
501         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
502         ///         using <see cref="StringComparer.Ordinal"/>.
503         ///     </para>
504         /// </remarks>
505         /// <exception cref="CompositionContractMismatchException">
506         ///     The underlying exported value cannot be cast to <typeparamref name="T"/>.
507         /// </exception>
508         /// <exception cref="ImportCardinalityMismatchException">
509         ///     <para>
510         ///         There are zero exported values with the specified contract name in the
511         ///         <see cref="CompositionContainer"/>.
512         ///     </para>
513         ///     -or-
514         ///     <para>
515         ///         There are more than one exported values with the specified contract name in the
516         ///         <see cref="CompositionContainer"/>.
517         ///     </para>
518         /// </exception>
519         /// <exception cref="ObjectDisposedException">
520         ///     The <see cref="CompositionContainer"/> has been disposed of.
521         /// </exception>
522         /// <exception cref="CompositionException">
523         ///     An error occurred during composition. <see cref="CompositionException.Errors"/> will
524         ///     contain a collection of errors that occurred.
525         /// </exception>
526         public T? GetExportedValue<T>(string? contractName)
527         {
528             return GetExportedValueCore<T>(contractName, ImportCardinality.ExactlyOne);
529         }
530
531         /// <summary>
532         ///     Returns the exported value with the contract name derived from the specified type
533         ///     parameter, throwing an exception if there is more than one matching exported value.
534         /// </summary>
535         /// <typeparam name="T">
536         ///     The type of the exported value to return. The contract name is also
537         ///     derived from this type parameter.
538         /// </typeparam>
539         /// <returns>
540         ///     The exported <see cref="object"/> with the contract name derived from
541         ///     <typeparamref name="T"/>, if found; otherwise, the default value for
542         ///     <typeparamref name="T"/>.
543         /// </returns>
544         /// <remarks>
545         ///     <para>
546         ///         If the exported value is not found, then this method returns the appropriate
547         ///         default value for <typeparamref name="T"/>; for example, 0 (zero) for integer
548         ///         types, <see langword="false"/> for Boolean types, and <see langword="null"/>
549         ///         for reference types.
550         ///     </para>
551         ///     <para>
552         ///         The contract name is the result of calling
553         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
554         ///     </para>
555         ///     <para>
556         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
557         ///         using <see cref="StringComparer.Ordinal"/>.
558         ///     </para>
559         /// </remarks>
560         /// <exception cref="CompositionContractMismatchException">
561         ///     The underlying exported value cannot be cast to <typeparamref name="T"/>.
562         /// </exception>
563         /// <exception cref="ImportCardinalityMismatchException">
564         ///     <para>
565         ///         There are more than one exported values with the contract name derived from
566         ///         <typeparamref name="T"/> in the <see cref="CompositionContainer"/>.
567         ///     </para>
568         /// </exception>
569         /// <exception cref="ObjectDisposedException">
570         ///     The <see cref="CompositionContainer"/> has been disposed of.
571         /// </exception>
572         /// <exception cref="CompositionException">
573         ///     An error occurred during composition. <see cref="CompositionException.Errors"/> will
574         ///     contain a collection of errors that occurred.
575         /// </exception>
576         public T? GetExportedValueOrDefault<T>()
577         {
578             return GetExportedValueOrDefault<T>((string?)null);
579         }
580
581         /// <summary>
582         ///     Returns the exported value with the specified contract name, throwing an exception
583         ///     if there is more than one matching exported value.
584         /// </summary>
585         /// <typeparam name="T">
586         ///     The type of the exported value to return.
587         /// </typeparam>
588         /// <param name="contractName">
589         ///     A <see cref="string"/> containing the contract name of the exported value to return,
590         ///     or <see langword="null"/> or an empty string ("") to use the default contract name.
591         /// </param>
592         /// <returns>
593         ///     The exported <see cref="object"/> with the specified contract name, if found;
594         ///     otherwise, the default value for <typeparamref name="T"/>.
595         /// </returns>
596         /// <remarks>
597         ///     <para>
598         ///         If the exported value is not found, then this method returns the appropriate
599         ///         default value for <typeparamref name="T"/>; for example, 0 (zero) for integer
600         ///         types, <see langword="false"/> for Boolean types, and <see langword="null"/>
601         ///         for reference types.
602         ///     </para>
603         ///     <para>
604         ///         The default contract name is the result of calling
605         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
606         ///     </para>
607         ///     <para>
608         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
609         ///         using <see cref="StringComparer.Ordinal"/>.
610         ///     </para>
611         /// </remarks>
612         /// <exception cref="CompositionContractMismatchException">
613         ///     The underlying exported value cannot be cast to <typeparamref name="T"/>.
614         /// </exception>
615         /// <exception cref="ImportCardinalityMismatchException">
616         ///     There are more than one exported values with the specified contract name in the
617         ///     <see cref="CompositionContainer"/>.
618         /// </exception>
619         /// <exception cref="ObjectDisposedException">
620         ///     The <see cref="CompositionContainer"/> has been disposed of.
621         /// </exception>
622         /// <exception cref="CompositionException">
623         ///     An error occurred during composition. <see cref="CompositionException.Errors"/> will
624         ///     contain a collection of errors that occurred.
625         /// </exception>
626         public T? GetExportedValueOrDefault<T>(string? contractName)
627         {
628             return GetExportedValueCore<T>(contractName, ImportCardinality.ZeroOrOne);
629         }
630
631         /// <summary>
632         ///     Returns the exported values with the contract name derived from the specified type
633         ///     parameter.
634         /// </summary>
635         /// <typeparam name="T">
636         ///     The type of the exported value to return. The contract name is also
637         ///     derived from this type parameter.
638         /// </typeparam>
639         /// <returns>
640         ///     An <see cref="Collection{T}"/> containing the exported values with the contract name
641         ///     derived from the specified type parameter, if found; otherwise, an empty
642         ///     <see cref="Collection{T}"/>.
643         /// </returns>
644         /// <remarks>
645         ///     <para>
646         ///         The contract name is the result of calling
647         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
648         ///     </para>
649         ///     <para>
650         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
651         ///         using <see cref="StringComparer.Ordinal"/>.
652         ///     </para>
653         /// </remarks>
654         /// <exception cref="CompositionContractMismatchException">
655         ///     One or more of the underlying exported values cannot be cast to
656         ///     <typeparamref name="T"/>.
657         /// </exception>
658         /// <exception cref="ObjectDisposedException">
659         ///     The <see cref="CompositionContainer"/> has been disposed of.
660         /// </exception>
661         /// <exception cref="CompositionException">
662         ///     An error occurred during composition. <see cref="CompositionException.Errors"/> will
663         ///     contain a collection of errors that occurred.
664         /// </exception>
665         public IEnumerable<T> GetExportedValues<T>()
666         {
667             return GetExportedValues<T>((string?)null);
668         }
669
670         /// <summary>
671         ///     Returns the exported values with the specified contract name.
672         /// </summary>
673         /// <typeparam name="T">
674         ///     The type of the exported value to return.
675         /// </typeparam>
676         /// <param name="contractName">
677         ///     A <see cref="string"/> containing the contract name of the exported values to
678         ///     return; or <see langword="null"/> or an empty string ("") to use the default
679         ///     contract name.
680         /// </param>
681         /// <returns>
682         ///     An <see cref="Collection{T}"/> containing the exported values with the specified
683         ///     contract name, if found; otherwise, an empty <see cref="Collection{T}"/>.
684         /// </returns>
685         /// <remarks>
686         ///     <para>
687         ///         The default contract name is the result of calling
688         ///         <see cref="AttributedModelServices.GetContractName(Type)"/> on <typeparamref name="T"/>.
689         ///     </para>
690         ///     <para>
691         ///         The contract name is compared using a case-sensitive, non-linguistic comparison
692         ///         using <see cref="StringComparer.Ordinal"/>.
693         ///     </para>
694         /// </remarks>
695         /// <exception cref="CompositionContractMismatchException">
696         ///     One or more of the underlying exported values cannot be cast to
697         ///     <typeparamref name="T"/>.
698         /// </exception>
699         /// <exception cref="ObjectDisposedException">
700         ///     The <see cref="CompositionContainer"/> has been disposed of.
701         /// </exception>
702         /// <exception cref="CompositionException">
703         ///     An error occurred during composition. <see cref="CompositionException.Errors"/> will
704         ///     contain a collection of errors that occurred.
705         /// </exception>
706         public IEnumerable<T> GetExportedValues<T>(string? contractName)
707         {
708             return GetExportedValuesCore<T>(contractName);
709         }
710
711         private IEnumerable<T> GetExportedValuesCore<T>(string? contractName)
712         {
713             IEnumerable<Export> exports = GetExportsCore(typeof(T), (Type?)null, contractName, ImportCardinality.ZeroOrMore);
714
715             Collection<T> result = new Collection<T>();
716             foreach (Export export in exports)
717             {
718                 result.Add(ExportServices.GetCastedExportedValue<T>(export));
719             }
720             return result;
721         }
722
723         private T? GetExportedValueCore<T>(string? contractName, ImportCardinality cardinality)
724         {
725             if (!cardinality.IsAtMostOne())
726             {
727                 throw new Exception(SR.Diagnostic_InternalExceptionMessage);
728             }
729
730             Export? export = GetExportsCore(typeof(T), (Type?)null, contractName, cardinality).SingleOrDefault();
731
732             return (export != null) ? ExportServices.GetCastedExportedValue<T>(export) : default;
733         }
734
735         private IEnumerable<Lazy<T>> GetExportsCore<T>(string? contractName)
736         {
737             IEnumerable<Export> exports = GetExportsCore(typeof(T), (Type?)null, contractName, ImportCardinality.ZeroOrMore);
738
739             Collection<Lazy<T>> result = new Collection<Lazy<T>>();
740             foreach (Export export in exports)
741             {
742                 result.Add(ExportServices.CreateStronglyTypedLazyOfT<T>(export));
743             }
744             return result;
745         }
746
747         private IEnumerable<Lazy<T, TMetadataView>> GetExportsCore<T, TMetadataView>(string? contractName)
748         {
749             IEnumerable<Export> exports = GetExportsCore(typeof(T), typeof(TMetadataView), contractName, ImportCardinality.ZeroOrMore);
750
751             Collection<Lazy<T, TMetadataView>> result = new Collection<Lazy<T, TMetadataView>>();
752             foreach (Export export in exports)
753             {
754                 result.Add(ExportServices.CreateStronglyTypedLazyOfTM<T, TMetadataView>(export));
755             }
756             return result;
757         }
758
759         private Lazy<T, TMetadataView>? GetExportCore<T, TMetadataView>(string? contractName)
760         {
761             Export? export = GetExportsCore(typeof(T), typeof(TMetadataView), contractName, ImportCardinality.ExactlyOne).SingleOrDefault();
762
763             return (export != null) ? ExportServices.CreateStronglyTypedLazyOfTM<T, TMetadataView>(export) : null;
764         }
765
766         private Lazy<T>? GetExportCore<T>(string? contractName)
767         {
768             Export? export = GetExportsCore(typeof(T), null, contractName, ImportCardinality.ExactlyOne).SingleOrDefault();
769
770             return (export != null) ? ExportServices.CreateStronglyTypedLazyOfT<T>(export) : null;
771         }
772
773         private IEnumerable<Export> GetExportsCore(Type type, Type? metadataViewType, string? contractName, ImportCardinality cardinality)
774         {
775             // Only 'type' cannot be null - the other parameters have sensible defaults.
776             Requires.NotNull(type, nameof(type));
777
778             if (string.IsNullOrEmpty(contractName))
779             {
780                 contractName = AttributedModelServices.GetContractName(type);
781             }
782
783             metadataViewType ??= ExportServices.DefaultMetadataViewType;
784
785             if (!MetadataViewProvider.IsViewTypeValid(metadataViewType))
786             {
787                 throw new InvalidOperationException(SR.Format(SR.InvalidMetadataView, metadataViewType.Name));
788             }
789
790             ImportDefinition importDefinition = BuildImportDefinition(type, metadataViewType, contractName, cardinality);
791             return GetExports(importDefinition, null);
792         }
793
794         private static ImportDefinition BuildImportDefinition(Type type, Type metadataViewType, string contractName, ImportCardinality cardinality)
795         {
796             ArgumentNullException.ThrowIfNull(type);
797             ArgumentNullException.ThrowIfNull(metadataViewType);
798             ArgumentNullException.ThrowIfNull(contractName);
799
800             IEnumerable<KeyValuePair<string, Type>> requiredMetadata = CompositionServices.GetRequiredMetadata(metadataViewType);
801             IDictionary<string, object?> metadata = CompositionServices.GetImportMetadata(type, null);
802
803             string? requiredTypeIdentity = null;
804             if (type != typeof(object))
805             {
806                 requiredTypeIdentity = AttributedModelServices.GetTypeIdentity(type);
807             }
808
809             return new ContractBasedImportDefinition(contractName, requiredTypeIdentity, requiredMetadata, cardinality, false, true, CreationPolicy.Any, metadata);
810         }
811     }
812 }