Fix pragma warning restore (dotnet/coreclr#26389)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / Resources / ResourceSet.cs
blob12cde70d0e67be629d3b8797804960e816d696a0
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 // See the LICENSE file in the project root for more information.
5 /*============================================================
6 **
7 **
8 **
9 **
11 ** Purpose: Culture-specific collection of resources.
14 ===========================================================*/
16 using System.Collections;
17 using System.Diagnostics;
18 using System.IO;
19 using System.Reflection;
21 namespace System.Resources
23 // A ResourceSet stores all the resources defined in one particular CultureInfo.
25 // The method used to load resources is straightforward - this class
26 // enumerates over an IResourceReader, loading every name and value, and
27 // stores them in a hash table. Custom IResourceReaders can be used.
29 public class ResourceSet : IDisposable, IEnumerable
31 protected IResourceReader Reader = null!;
32 internal Hashtable? Table; // TODO-NULLABLE: Avoid nulling out in Dispose
34 private Hashtable? _caseInsensitiveTable; // For case-insensitive lookups.
36 protected ResourceSet()
38 // To not inconvenience people subclassing us, we should allocate a new
39 // hashtable here just so that Table is set to something.
40 Table = new Hashtable();
43 // For RuntimeResourceSet, ignore the Table parameter - it's a wasted
44 // allocation.
45 internal ResourceSet(bool junk)
49 // Creates a ResourceSet using the system default ResourceReader
50 // implementation. Use this constructor to open & read from a file
51 // on disk.
53 public ResourceSet(string fileName)
54 : this()
56 Reader = new ResourceReader(fileName);
57 ReadResources();
60 // Creates a ResourceSet using the system default ResourceReader
61 // implementation. Use this constructor to read from an open stream
62 // of data.
64 public ResourceSet(Stream stream)
65 : this()
67 Reader = new ResourceReader(stream);
68 ReadResources();
71 public ResourceSet(IResourceReader reader)
72 : this()
74 if (reader == null)
75 throw new ArgumentNullException(nameof(reader));
76 Reader = reader;
77 ReadResources();
80 // Closes and releases any resources used by this ResourceSet, if any.
81 // All calls to methods on the ResourceSet after a call to close may
82 // fail. Close is guaranteed to be safely callable multiple times on a
83 // particular ResourceSet, and all subclasses must support these semantics.
84 public virtual void Close()
86 Dispose(true);
89 protected virtual void Dispose(bool disposing)
91 if (disposing)
93 // Close the Reader in a thread-safe way.
94 IResourceReader? copyOfReader = Reader;
95 Reader = null!; // TODO-NULLABLE: Avoid nulling out in Dispose
96 if (copyOfReader != null)
97 copyOfReader.Close();
99 Reader = null!; // TODO-NULLABLE: Avoid nulling out in Dispose
100 _caseInsensitiveTable = null;
101 Table = null;
104 public void Dispose()
106 Dispose(true);
109 // Returns the preferred IResourceReader class for this kind of ResourceSet.
110 // Subclasses of ResourceSet using their own Readers &; should override
111 // GetDefaultReader and GetDefaultWriter.
112 public virtual Type GetDefaultReader()
114 return typeof(ResourceReader);
117 // Returns the preferred IResourceWriter class for this kind of ResourceSet.
118 // Subclasses of ResourceSet using their own Readers &; should override
119 // GetDefaultReader and GetDefaultWriter.
120 public virtual Type GetDefaultWriter()
122 Assembly resourceWriterAssembly = Assembly.Load("System.Resources.Writer, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
123 return resourceWriterAssembly.GetType("System.Resources.ResourceWriter", throwOnError: true)!;
126 public virtual IDictionaryEnumerator GetEnumerator()
128 return GetEnumeratorHelper();
131 IEnumerator IEnumerable.GetEnumerator()
133 return GetEnumeratorHelper();
136 private IDictionaryEnumerator GetEnumeratorHelper()
138 Hashtable? copyOfTable = Table; // Avoid a race with Dispose
139 if (copyOfTable == null)
140 throw new ObjectDisposedException(null, SR.ObjectDisposed_ResourceSet);
141 return copyOfTable.GetEnumerator();
144 // Look up a string value for a resource given its name.
146 public virtual string? GetString(string name)
148 object? obj = GetObjectInternal(name);
151 return (string?)obj;
153 catch (InvalidCastException)
155 throw new InvalidOperationException(SR.Format(SR.InvalidOperation_ResourceNotString_Name, name));
159 public virtual string? GetString(string name, bool ignoreCase)
161 object? obj;
162 string? s;
164 // Case-sensitive lookup
165 obj = GetObjectInternal(name);
168 s = (string?)obj;
170 catch (InvalidCastException)
172 throw new InvalidOperationException(SR.Format(SR.InvalidOperation_ResourceNotString_Name, name));
175 // case-sensitive lookup succeeded
176 if (s != null || !ignoreCase)
178 return s;
181 // Try doing a case-insensitive lookup
182 obj = GetCaseInsensitiveObjectInternal(name);
185 return (string?)obj;
187 catch (InvalidCastException)
189 throw new InvalidOperationException(SR.Format(SR.InvalidOperation_ResourceNotString_Name, name));
193 // Look up an object value for a resource given its name.
195 public virtual object? GetObject(string name)
197 return GetObjectInternal(name);
200 public virtual object? GetObject(string name, bool ignoreCase)
202 object? obj = GetObjectInternal(name);
204 if (obj != null || !ignoreCase)
205 return obj;
207 return GetCaseInsensitiveObjectInternal(name);
210 protected virtual void ReadResources()
212 Debug.Assert(Table != null);
213 Debug.Assert(Reader != null);
214 IDictionaryEnumerator en = Reader.GetEnumerator();
215 while (en.MoveNext())
217 object? value = en.Value;
218 Table.Add(en.Key, value);
220 // While technically possible to close the Reader here, don't close it
221 // to help with some WinRes lifetime issues.
224 private object? GetObjectInternal(string name)
226 if (name == null)
227 throw new ArgumentNullException(nameof(name));
229 Hashtable? copyOfTable = Table; // Avoid a race with Dispose
231 if (copyOfTable == null)
232 throw new ObjectDisposedException(null, SR.ObjectDisposed_ResourceSet);
234 return copyOfTable[name];
237 private object? GetCaseInsensitiveObjectInternal(string name)
239 Hashtable? copyOfTable = Table; // Avoid a race with Dispose
241 if (copyOfTable == null)
242 throw new ObjectDisposedException(null, SR.ObjectDisposed_ResourceSet);
244 Hashtable? caseTable = _caseInsensitiveTable; // Avoid a race condition with Close
245 if (caseTable == null)
247 caseTable = new Hashtable(StringComparer.OrdinalIgnoreCase);
249 IDictionaryEnumerator en = copyOfTable.GetEnumerator();
250 while (en.MoveNext())
252 caseTable.Add(en.Key, en.Value);
254 _caseInsensitiveTable = caseTable;
257 return caseTable[name];