Implement MachineKey.Protect and MachineKey.Unprotect
[mono.git] / mcs / class / System.ComponentModel.Composition / src / ComponentModel / System / ComponentModel / Composition / Primitives / Export.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.Diagnostics.CodeAnalysis;\r
7 using Microsoft.Internal;\r
8 using System.Threading;\r
9 \r
10 namespace System.ComponentModel.Composition.Primitives\r
11 {\r
12     /// <summary>\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
15     /// </summary>\r
16     public class Export\r
17     {\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
22         \r
23         /// <summary>\r
24         ///     Initializes a new instance of the <see cref="Export"/> class.\r
25         /// </summary>\r
26         /// <remarks>\r
27         ///     <note type="inheritinfo">\r
28         ///         Derived types calling this constructor must override <see cref="Definition"/>\r
29         ///         and <see cref="GetExportedValueCore"/>.\r
30         ///     </note>\r
31         /// </remarks>\r
32         protected Export()\r
33         {\r
34         }\r
35 \r
36         /// <summary>\r
37         ///     Initializes a new instance of the <see cref="Export"/> class \r
38         ///     with the specified contract name and exported value getter.\r
39         /// </summary>\r
40         /// <param name="contractName">\r
41         ///     A <see cref="String"/> containing the contract name of the \r
42         ///     <see cref="Export"/>.\r
43         /// </param>\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
47         /// </param>\r
48         /// <exception cref="ArgumentNullException">\r
49         ///     <paramref name="contractName"/> is <see langword="null"/>.\r
50         ///     <para>\r
51         ///         -or-\r
52         ///     </para>\r
53         ///     <paramref name="exportedValueGetter"/> is <see langword="null"/>.\r
54         /// </exception>\r
55         /// <exception cref="ArgumentException">\r
56         ///     <paramref name="contractName"/> is an empty string ("").\r
57         /// </exception>\r
58         public Export(string contractName, Func<object> exportedValueGetter)\r
59             : this(new ExportDefinition(contractName, (IDictionary<string, object>)null), exportedValueGetter)\r
60         {\r
61         }\r
62 \r
63         /// <summary>\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
66         /// </summary>\r
67         /// <param name="contractName">\r
68         ///     A <see cref="String"/> containing the contract name of the \r
69         ///     <see cref="Export"/>.\r
70         /// </param>\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
76         /// </param>\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
80         /// </param>\r
81         /// <exception cref="ArgumentNullException">\r
82         ///     <paramref name="contractName"/> is <see langword="null"/>.\r
83         ///     <para>\r
84         ///         -or-\r
85         ///     </para>\r
86         ///     <paramref name="exportedValueGetter"/> is <see langword="null"/>.\r
87         /// </exception>\r
88         /// <exception cref="ArgumentException">\r
89         ///     <paramref name="contractName"/> is an empty string ("").\r
90         /// </exception>\r
91         public Export(string contractName, IDictionary<string, object> metadata, Func<object> exportedValueGetter) \r
92             : this(new ExportDefinition(contractName, metadata), exportedValueGetter)\r
93         {\r
94         }\r
95 \r
96         /// <summary>\r
97         ///     Initializes a new instance of the <see cref="Export"/> class \r
98         ///     with the specified export definition and exported value getter.\r
99         /// </summary>\r
100         /// <param name="definition">\r
101         ///     An <see cref="ExportDefinition"/> that describes the contract that the \r
102         ///     <see cref="Export"/> satisfies.\r
103         /// </param>\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
107         /// </param>\r
108         /// <exception cref="ArgumentNullException">\r
109         ///     <paramref name="definition"/> is <see langword="null"/>.\r
110         ///     <para>\r
111         ///         -or-\r
112         ///     </para>\r
113         ///     <paramref name="exportedValueGetter"/> is <see langword="null"/>.\r
114         /// </exception>\r
115         public Export(ExportDefinition definition, Func<object> exportedValueGetter)\r
116         {\r
117             Requires.NotNull(definition, "definition");\r
118             Requires.NotNull(exportedValueGetter, "exportedValueGetter");\r
119 \r
120             this._definition = definition;\r
121             this._exportedValueGetter = exportedValueGetter;\r
122         }\r
123 \r
124         /// <summary>\r
125         ///     Gets the definition that describes the contract that the export satisfies.\r
126         /// </summary>\r
127         /// <value>\r
128         ///     An <see cref="ExportDefinition"/> that describes the contract that \r
129         ///     the <see cref="Export"/> satisfies.\r
130         /// </value>\r
131         /// <exception cref="NotImplementedException">\r
132         ///     This property was not overridden by a derived class.\r
133         /// </exception>\r
134         /// <remarks>\r
135         ///     <note type="inheritinfo">\r
136         ///         Overriders of this property should never return\r
137         ///         <see langword="null"/>.\r
138         ///     </note>\r
139         /// </remarks>\r
140         public virtual ExportDefinition Definition\r
141         {\r
142             get \r
143             {\r
144                 if (_definition != null)\r
145                 {\r
146                     return _definition;\r
147                 }\r
148 \r
149                 throw ExceptionBuilder.CreateNotOverriddenByDerived("Definition");\r
150             }\r
151         }\r
152 \r
153         /// <summary>\r
154         ///     Gets the metadata of the export.\r
155         /// </summary>\r
156         /// <value>\r
157         ///     An <see cref="IDictionary{TKey, TValue}"/> containing the metadata of the \r
158         ///     <see cref="Export"/>.\r
159         /// </value>\r
160         /// <exception cref="NotImplementedException">\r
161         ///     The <see cref="Definition"/> property was not overridden by a derived class.\r
162         /// </exception>\r
163         /// <remarks>\r
164         ///     <para>\r
165         ///         This property returns the value of <see cref="ExportDefinition.Metadata"/>\r
166         ///         of the <see cref="Definition"/> property.\r
167         ///     </para>\r
168         /// </remarks>\r
169         public IDictionary<string, object> Metadata\r
170         {\r
171             get { return Definition.Metadata; }\r
172         }\r
173 \r
174         /// <summary>\r
175         ///     Returns the exported value of the export.\r
176         /// </summary>\r
177         /// <returns>\r
178         ///     The exported <see cref="Object"/> of the <see cref="Export"/>.\r
179         /// </returns>\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
183         /// </exception>\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
187         /// </exception>\r
188         /// <exception cref="NotImplementedException">\r
189         ///     The <see cref="GetExportedValueCore"/> method was not overridden by a derived class.\r
190         /// </exception>\r
191         public object Value\r
192         {\r
193             get\r
194             {\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
198                 {\r
199                     object exportedValue = this.GetExportedValueCore();\r
200 \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
205                 }\r
206 \r
207                 return this._exportedValue;\r
208             }\r
209         }\r
210 \r
211         /// <summary>\r
212         ///     Returns the exported value of the export.\r
213         /// </summary>\r
214         /// <returns>\r
215         ///     The exported <see cref="Object"/> of the <see cref="Export"/>.\r
216         /// </returns>\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
220         /// </exception>\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
224         /// </exception>\r
225         /// <exception cref="NotImplementedException">\r
226         ///     The method was not overridden by a derived class.\r
227         /// </exception>\r
228         /// <remarks>\r
229         ///     <note type="inheritinfo">\r
230         ///         Overriders of this method should never return\r
231         ///         <see langword="null"/>.\r
232         ///     </note>\r
233         /// </remarks>\r
234         [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]\r
235         protected virtual object GetExportedValueCore()\r
236         {\r
237             if (this._exportedValueGetter != null)\r
238             {\r
239                 return this._exportedValueGetter.Invoke();\r
240             }\r
241 \r
242             throw ExceptionBuilder.CreateNotOverriddenByDerived("GetExportedValueCore");\r
243         }\r
244     }   \r
245 }\r