1 // -----------------------------------------------------------------------
\r
2 // Copyright (c) Microsoft Corporation. All rights reserved.
\r
3 // -----------------------------------------------------------------------
\r
5 using System.Collections.Generic;
\r
6 using System.Diagnostics.CodeAnalysis;
\r
7 using Microsoft.Internal;
\r
8 using System.Threading;
\r
10 namespace System.ComponentModel.Composition.Primitives
\r
13 /// Represents an export. That is, a type that is made up of a delay-created exported value
\r
14 /// and metadata that describes that object.
\r
18 private readonly ExportDefinition _definition;
\r
19 private readonly Func<object> _exportedValueGetter;
\r
20 private static readonly object _EmptyValue = new object();
\r
21 private volatile object _exportedValue = Export._EmptyValue;
\r
24 /// Initializes a new instance of the <see cref="Export"/> class.
\r
27 /// <note type="inheritinfo">
\r
28 /// Derived types calling this constructor must override <see cref="Definition"/>
\r
29 /// and <see cref="GetExportedValueCore"/>.
\r
37 /// Initializes a new instance of the <see cref="Export"/> class
\r
38 /// with the specified contract name and exported value getter.
\r
40 /// <param name="contractName">
\r
41 /// A <see cref="String"/> containing the contract name of the
\r
42 /// <see cref="Export"/>.
\r
44 /// <param name="exportedValueGetter">
\r
45 /// A <see cref="Func{T}"/> that is called to create the exported value of the
\r
46 /// <see cref="Export"/>. This allows the creation of the object to be delayed
\r
48 /// <exception cref="ArgumentNullException">
\r
49 /// <paramref name="contractName"/> is <see langword="null"/>.
\r
53 /// <paramref name="exportedValueGetter"/> is <see langword="null"/>.
\r
55 /// <exception cref="ArgumentException">
\r
56 /// <paramref name="contractName"/> is an empty string ("").
\r
58 public Export(string contractName, Func<object> exportedValueGetter)
\r
59 : this(new ExportDefinition(contractName, (IDictionary<string, object>)null), exportedValueGetter)
\r
64 /// Initializes a new instance of the <see cref="Export"/> class
\r
65 /// with the specified contract name, metadata and exported value getter.
\r
67 /// <param name="contractName">
\r
68 /// A <see cref="String"/> containing the contract name of the
\r
69 /// <see cref="Export"/>.
\r
71 /// <param name="metadata">
\r
72 /// An <see cref="IDictionary{TKey, TValue}"/> containing the metadata of the
\r
73 /// <see cref="Export"/>; or <see langword="null"/> to set the
\r
74 /// <see cref="Metadata"/> property to an empty, read-only
\r
75 /// <see cref="IDictionary{TKey, TValue}"/>.
\r
77 /// <param name="exportedValueGetter">
\r
78 /// A <see cref="Func{T}"/> that is called to create the exported value of the
\r
79 /// <see cref="Export"/>. This allows the creation of the object to be delayed.
\r
81 /// <exception cref="ArgumentNullException">
\r
82 /// <paramref name="contractName"/> is <see langword="null"/>.
\r
86 /// <paramref name="exportedValueGetter"/> is <see langword="null"/>.
\r
88 /// <exception cref="ArgumentException">
\r
89 /// <paramref name="contractName"/> is an empty string ("").
\r
91 public Export(string contractName, IDictionary<string, object> metadata, Func<object> exportedValueGetter)
\r
92 : this(new ExportDefinition(contractName, metadata), exportedValueGetter)
\r
97 /// Initializes a new instance of the <see cref="Export"/> class
\r
98 /// with the specified export definition and exported value getter.
\r
100 /// <param name="definition">
\r
101 /// An <see cref="ExportDefinition"/> that describes the contract that the
\r
102 /// <see cref="Export"/> satisfies.
\r
104 /// <param name="exportedValueGetter">
\r
105 /// A <see cref="Func{T}"/> that is called to create the exported value of the
\r
106 /// <see cref="Export"/>. This allows the creation of the object to be delayed.
\r
108 /// <exception cref="ArgumentNullException">
\r
109 /// <paramref name="definition"/> is <see langword="null"/>.
\r
113 /// <paramref name="exportedValueGetter"/> is <see langword="null"/>.
\r
115 public Export(ExportDefinition definition, Func<object> exportedValueGetter)
\r
117 Requires.NotNull(definition, "definition");
\r
118 Requires.NotNull(exportedValueGetter, "exportedValueGetter");
\r
120 this._definition = definition;
\r
121 this._exportedValueGetter = exportedValueGetter;
\r
125 /// Gets the definition that describes the contract that the export satisfies.
\r
128 /// An <see cref="ExportDefinition"/> that describes the contract that
\r
129 /// the <see cref="Export"/> satisfies.
\r
131 /// <exception cref="NotImplementedException">
\r
132 /// This property was not overridden by a derived class.
\r
135 /// <note type="inheritinfo">
\r
136 /// Overriders of this property should never return
\r
137 /// <see langword="null"/>.
\r
140 public virtual ExportDefinition Definition
\r
144 if (_definition != null)
\r
146 return _definition;
\r
149 throw ExceptionBuilder.CreateNotOverriddenByDerived("Definition");
\r
154 /// Gets the metadata of the export.
\r
157 /// An <see cref="IDictionary{TKey, TValue}"/> containing the metadata of the
\r
158 /// <see cref="Export"/>.
\r
160 /// <exception cref="NotImplementedException">
\r
161 /// The <see cref="Definition"/> property was not overridden by a derived class.
\r
165 /// This property returns the value of <see cref="ExportDefinition.Metadata"/>
\r
166 /// of the <see cref="Definition"/> property.
\r
169 public IDictionary<string, object> Metadata
\r
171 get { return Definition.Metadata; }
\r
175 /// Returns the exported value of the export.
\r
178 /// The exported <see cref="Object"/> of the <see cref="Export"/>.
\r
180 /// <exception cref="CompositionException">
\r
181 /// An error occurred during composition. <see cref="CompositionException.Errors"/> will
\r
182 /// contain a collection of errors that occurred.
\r
184 /// <exception cref="CompositionContractMismatchException">
\r
185 /// The current instance is an instance of <see cref="Lazy{T}"/> and the underlying
\r
186 /// exported value cannot be cast to <c>T</c>.
\r
188 /// <exception cref="NotImplementedException">
\r
189 /// The <see cref="GetExportedValueCore"/> method was not overridden by a derived class.
\r
191 public object Value
\r
195 // NOTE : the logic below guarantees that the value will be set exactly once. It DOES NOT, however, guarantee that GetExportedValueCore() will be executed
\r
196 // more than once, as locking would be required for that. The said locking is problematic, as we can't reliable call 3rd party code under a lock.
\r
197 if (this._exportedValue == Export._EmptyValue)
\r
199 object exportedValue = this.GetExportedValueCore();
\r
201 // NOTE : According to http://msdn.microsoft.com/en-us/library/4bw5ewxy.aspx, the warning is bogus when used with Interlocked API.
\r
202 #pragma warning disable 420
\r
203 Interlocked.CompareExchange(ref this._exportedValue, exportedValue, Export._EmptyValue);
\r
204 #pragma warning restore 420
\r
207 return this._exportedValue;
\r
212 /// Returns the exported value of the export.
\r
215 /// The exported <see cref="Object"/> of the <see cref="Export"/>.
\r
217 /// <exception cref="CompositionException">
\r
218 /// An error occurred during composition. <see cref="CompositionException.Errors"/> will
\r
219 /// contain a collection of errors that occurred.
\r
221 /// <exception cref="CompositionContractMismatchException">
\r
222 /// The current instance is an instance of <see cref="Lazy{T}"/> and the underlying
\r
223 /// exported value cannot be cast to <c>T</c>.
\r
225 /// <exception cref="NotImplementedException">
\r
226 /// The method was not overridden by a derived class.
\r
229 /// <note type="inheritinfo">
\r
230 /// Overriders of this method should never return
\r
231 /// <see langword="null"/>.
\r
234 [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
\r
235 protected virtual object GetExportedValueCore()
\r
237 if (this._exportedValueGetter != null)
\r
239 return this._exportedValueGetter.Invoke();
\r
242 throw ExceptionBuilder.CreateNotOverriddenByDerived("GetExportedValueCore");
\r