3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
10 ** <OWNER>[....]</OWNER>
13 ** Purpose: Culture-specific collection of resources.
16 ===========================================================*/
17 namespace System.Resources {
19 using System.Collections;
21 using System.Globalization;
22 using System.Security.Permissions;
23 using System.Runtime.InteropServices;
24 using System.Reflection;
25 using System.Runtime.Serialization;
26 using System.Runtime.Versioning;
27 using System.Diagnostics.Contracts;
29 // A ResourceSet stores all the resources defined in one particular CultureInfo.
31 // The method used to load resources is straightforward - this class
32 // enumerates over an IResourceReader, loading every name and value, and
33 // stores them in a hash table. Custom IResourceReaders can be used.
36 [System.Runtime.InteropServices.ComVisible(true)]
37 public class ResourceSet : IDisposable, IEnumerable
39 [NonSerialized] protected IResourceReader Reader;
41 internal Hashtable Table;
43 protected Hashtable Table;
46 private Hashtable _caseInsensitiveTable; // For case-insensitive lookups.
48 #if LOOSELY_LINKED_RESOURCE_REFERENCE
50 private Assembly _assembly; // For LooselyLinkedResourceReferences
51 #endif // LOOSELY_LINKED_RESOURCE_REFERENCE
53 protected ResourceSet()
55 // To not inconvenience people subclassing us, we should allocate a new
56 // hashtable here just so that Table is set to something.
60 // For RuntimeResourceSet, ignore the Table parameter - it's a wasted
62 internal ResourceSet(bool junk)
66 // Creates a ResourceSet using the system default ResourceReader
67 // implementation. Use this constructor to open & read from a file
71 [System.Security.SecurityCritical] // auto-generated
73 [ResourceExposure(ResourceScope.Machine)]
74 [ResourceConsumption(ResourceScope.Machine)]
75 public ResourceSet(String fileName)
77 Reader = new ResourceReader(fileName);
82 #if LOOSELY_LINKED_RESOURCE_REFERENCE
83 public ResourceSet(String fileName, Assembly assembly)
85 Reader = new ResourceReader(fileName);
90 #endif // LOOSELY_LINKED_RESOURCE_REFERENCE
92 // Creates a ResourceSet using the system default ResourceReader
93 // implementation. Use this constructor to read from an open stream
96 [System.Security.SecurityCritical] // auto-generated_required
97 public ResourceSet(Stream stream)
99 Reader = new ResourceReader(stream);
104 #if LOOSELY_LINKED_RESOURCE_REFERENCE
105 [System.Security.SecurityCritical] // auto_generated_required
106 public ResourceSet(Stream stream, Assembly assembly)
108 Reader = new ResourceReader(stream);
110 _assembly = assembly;
113 #endif // LOOSELY_LINKED_RESOURCE_REFERENCE
115 public ResourceSet(IResourceReader reader)
118 throw new ArgumentNullException("reader");
119 Contract.EndContractBlock();
125 #if LOOSELY_LINKED_RESOURCE_REFERENCE
126 public ResourceSet(IResourceReader reader, Assembly assembly)
129 throw new ArgumentNullException("reader");
130 Contract.EndContractBlock();
133 _assembly = assembly;
136 #endif // LOOSELY_LINKED_RESOURCE_REFERENCE
138 private void CommonInit()
140 Table = new Hashtable();
143 // Closes and releases any resources used by this ResourceSet, if any.
144 // All calls to methods on the ResourceSet after a call to close may
145 // fail. Close is guaranteed to be safely callable multiple times on a
146 // particular ResourceSet, and all subclasses must support these semantics.
147 public virtual void Close()
152 protected virtual void Dispose(bool disposing)
155 // Close the Reader in a thread-safe way.
156 IResourceReader copyOfReader = Reader;
158 if (copyOfReader != null)
159 copyOfReader.Close();
162 _caseInsensitiveTable = null;
166 public void Dispose()
171 #if LOOSELY_LINKED_RESOURCE_REFERENCE
172 // Optional - used for resolving assembly manifest resource references.
173 // This can safely be null.
175 public Assembly Assembly {
176 get { return _assembly; }
177 /*protected*/ set { _assembly = value; }
179 #endif // LOOSELY_LINKED_RESOURCE_REFERENCE
181 // Returns the preferred IResourceReader class for this kind of ResourceSet.
182 // Subclasses of ResourceSet using their own Readers &; should override
183 // GetDefaultReader and GetDefaultWriter.
184 public virtual Type GetDefaultReader()
186 return typeof(ResourceReader);
190 // Returns the preferred IResourceWriter class for this kind of ResourceSet.
191 // Subclasses of ResourceSet using their own Readers &; should override
192 // GetDefaultReader and GetDefaultWriter.
193 public virtual Type GetDefaultWriter()
195 return typeof(ResourceWriter);
197 #endif // !FEATURE_CORECLR
200 public virtual IDictionaryEnumerator GetEnumerator()
202 return GetEnumeratorHelper();
206 IEnumerator IEnumerable.GetEnumerator()
208 return GetEnumeratorHelper();
211 private IDictionaryEnumerator GetEnumeratorHelper()
213 Hashtable copyOfTable = Table; // Avoid a race with Dispose
214 if (copyOfTable == null)
215 throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_ResourceSet"));
216 return copyOfTable.GetEnumerator();
219 // Look up a string value for a resource given its name.
221 public virtual String GetString(String name)
223 Object obj = GetObjectInternal(name);
227 catch (InvalidCastException) {
228 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceNotString_Name", name));
232 public virtual String GetString(String name, bool ignoreCase)
237 // Case-sensitive lookup
238 obj = GetObjectInternal(name);
242 catch (InvalidCastException) {
243 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceNotString_Name", name));
246 // case-sensitive lookup succeeded
247 if (s != null || !ignoreCase) {
251 // Try doing a case-insensitive lookup
252 obj = GetCaseInsensitiveObjectInternal(name);
256 catch (InvalidCastException) {
257 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResourceNotString_Name", name));
261 // Look up an object value for a resource given its name.
263 public virtual Object GetObject(String name)
265 return GetObjectInternal(name);
268 public virtual Object GetObject(String name, bool ignoreCase)
270 Object obj = GetObjectInternal(name);
272 if (obj != null || !ignoreCase)
275 return GetCaseInsensitiveObjectInternal(name);
278 protected virtual void ReadResources()
280 IDictionaryEnumerator en = Reader.GetEnumerator();
281 while (en.MoveNext()) {
282 Object value = en.Value;
283 #if LOOSELY_LINKED_RESOURCE_REFERENCE
284 if (Assembly != null && value is LooselyLinkedResourceReference) {
285 LooselyLinkedResourceReference assRef = (LooselyLinkedResourceReference) value;
286 value = assRef.Resolve(Assembly);
288 #endif //LOOSELYLINKEDRESOURCEREFERENCE
289 Table.Add(en.Key, value);
291 // While technically possible to close the Reader here, don't close it
292 // to help with some WinRes lifetime issues.
295 private Object GetObjectInternal(String name)
298 throw new ArgumentNullException("name");
299 Contract.EndContractBlock();
301 Hashtable copyOfTable = Table; // Avoid a race with Dispose
303 if (copyOfTable == null)
304 throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_ResourceSet"));
306 return copyOfTable[name];
309 private Object GetCaseInsensitiveObjectInternal(String name)
311 Hashtable copyOfTable = Table; // Avoid a race with Dispose
313 if (copyOfTable == null)
314 throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_ResourceSet"));
316 Hashtable caseTable = _caseInsensitiveTable; // Avoid ---- with Close
317 if (caseTable == null)
319 caseTable = new Hashtable(StringComparer.OrdinalIgnoreCase);
321 //Console.WriteLine("ResourceSet::GetObject loading up case-insensitive data");
322 BCLDebug.Perf(false, "Using case-insensitive lookups is bad perf-wise. Consider capitalizing "+name+" correctly in your source");
325 IDictionaryEnumerator en = copyOfTable.GetEnumerator();
326 while (en.MoveNext())
328 caseTable.Add(en.Key, en.Value);
330 _caseInsensitiveTable = caseTable;
333 return caseTable[name];