Note
This class is similar to System.Resources.ResXResourceSet
in System.Windows.Forms.dll. See the Comparison with System.Resources.ResXResourceSet section for the differences.
[SerializableAttribute]
public sealed class ResXResourceSet : ResourceSet,
IExpandoResourceSet, IDisposable, IEnumerable
<SerializableAttribute>
Public NotInheritable Class ResXResourceSet
Inherits ResourceSet
Implements IExpandoResourceSet, IDisposable, IEnumerable
[SerializableAttribute]
public ref class ResXResourceSet sealed : public ResourceSet,
IExpandoResourceSet, IDisposable, IEnumerable
[<SealedAttribute>]
[<SerializableAttribute>]
type ResXResourceSet =
class
inherit ResourceSet
interface IExpandoResourceSet
interface IDisposable
interface IEnumerable
end
The ResXResourceSet class represents a single XML resource file (.resx file) in memory. It uses ResXResourceReader internally to read the .resx content and ResXResourceWriter to save it.
A ResXResourceSet instance can contain resources, metadata and aliases (unlike the System.Resources.ResXResourceSet class, which contains only the resources). These contents are available either by enumerators (GetEnumerator, GetMetadataEnumerator and GetAliasEnumerator methods) or directly by key (GetString and GetObject methods for resources, GetMetaString and GetMetaObject for metadata, and GetAliasValue for aliases).
The following example demonstrates how to access the content of a .resx file by the ResXResourceSet class using the enumerators. This is very similar to the first example of ResXResourceReader.
using System;
using System.Collections;
using System.IO;
using KGySoft.Resources;
public class Example
{
private const string resx = @"<?xml version='1.0' encoding='utf-8'?>
<root>
<data name='string'>
<value>Test string</value>
<comment>Default data type is string.</comment>
</data>
<metadata name='meta string'>
<value>Meta String</value>
</metadata>
<data name='int' type='System.Int32'>
<value>42</value>
</data>
<assembly alias='CustomAlias' name='System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' />
<data name='color' type='System.Drawing.Color, CustomAlias'>
<value>Red</value>
<comment>When this entry is deserialized, System.Drawing assembly will be loaded.</comment>
</data>
<data name='bytes' type='System.Byte[]'>
<value>VGVzdCBieXRlcw==</value>
</data>
<data name='dangerous' mimetype='application/x-microsoft.net.object.binary.base64'>
<value>YmluYXJ5</value>
<comment>BinaryFormatter will throw an exception for this invalid content.</comment>
</data>
</root>";
public static void Main()
{
var set = new ResXResourceSet(new StringReader(resx));
Console.WriteLine("____Resources in .resx:____");
Dump(set, set.GetEnumerator);
Console.WriteLine("____Metadata in .resx:____");
Dump(set, set.GetMetadataEnumerator);
Console.WriteLine("____Aliases in .resx:____");
Dump(set, set.GetAliasEnumerator);
}
private static void Dump(ResXResourceSet set, Func<IDictionaryEnumerator> getEnumeratorFunction)
{
var enumerator = getEnumeratorFunction();
while (enumerator.MoveNext())
{
Console.WriteLine($"Name: {enumerator.Key}");
set.SafeMode = true;
Console.WriteLine($" Value in SafeMode: {enumerator.Value} ({enumerator.Value.GetType()})");
try
{
set.SafeMode = false;
Console.WriteLine($" Value in non-SafeMode: {enumerator.Value} ({enumerator.Value.GetType()})");
}
catch (Exception e)
{
Console.WriteLine($"Getting the deserialized value thrown an exception: {e.Message}");
}
Console.WriteLine();
}
}
}
// The example displays the following output:
// ____Resources in .resx:____
// Name: string
// Value in SafeMode: Test string (KGySoft.Resources.ResXDataNode)
// Value in non-SafeMode: Test string (System.String)
// Name: int
// Value in SafeMode: 42 (KGySoft.Resources.ResXDataNode)
// Value in non-SafeMode: 42 (System.Int32)
// Name: color
// Value in SafeMode: Red (KGySoft.Resources.ResXDataNode)
// Value in non-SafeMode: Color[Red] (System.Drawing.Color)
// Name: bytes
// Value in SafeMode: VGVzdCBieXRlcw== (KGySoft.Resources.ResXDataNode)
// Value in non-SafeMode: System.Byte[] (System.Byte[])
// Name: dangerous
// Value in SafeMode: YmluYXJ5 (KGySoft.Resources.ResXDataNode)
// Getting the deserialized value thrown an exception: End of Stream encountered before parsing was completed.
// ____Metadata in .resx:____
// Name: meta string
// Value in SafeMode: Meta String (KGySoft.Resources.ResXDataNode)
// Value in non-SafeMode: Meta String (System.String)
// ____Aliases in .resx:____
// Name: CustomAlias
// Value in SafeMode: System.Drawing, Version= 4.0.0.0, Culture= neutral, PublicKeyToken= b03f5f7f11d50a3a (System.String)
// Value in non-SafeMode: System.Drawing, Version= 4.0.0.0, Culture= neutral, PublicKeyToken= b03f5f7f11d50a3a (System.String)
The ResXResourceSet class supports adding new resources (SetObject), metadata (SetMetaObject) and aliases (SetAliasValue). Existing entries can be removed by RemoveObject, RemoveMetaObject and RemoveAliasValue methods. The changed set can be saved by the Save overloads.
The following example shows how to create a new resource set, add a new resource and save the content. It demonstrates the usage of the key-based resource access, too.
using System;
using System.IO;
using System.Text;
using KGySoft.Resources;
public class Example
{
public static void Main()
{
const string key = "myKey";
var set = new ResXResourceSet();
// GetString/GetObject: reads a resource by key (GetMetaString/GetMetaObject for metadata, GetAliasValue for alias)
Console.WriteLine($"Getting a non-existing key: {set.GetString(key) ?? "<null>"}");
// SetObject: adds a new resource or replaces an existing one (SetMetaObject for metadata, SetAliasValue for assembly alias)
// you can even remove entries by RemoveObject/RemoveMetaObject/RemoveAliasValue)
set.SetObject(key, "a string value");
Console.WriteLine($"Getting an existing key: {set.GetString(key) ?? "<null>"}");
var savedContent = new StringBuilder();
set.Save(new StringWriter(savedContent), compatibleFormat: false); // try compatibleFormat: true as well
Console.WriteLine("Saved .resx content:");
Console.WriteLine(savedContent);
}
}
// The example displays the following output:
// Getting a non-existing key: <null>
// Getting an existing key: a string value
// Saved .resx content:
// <?xml version="1.0" encoding="utf-8"?>
// <root>
// <data name="myKey">
// <value>a string value</value>
// </data>
// </root>
If a .resx content contains the same resource name multiple times, ResXResourceSet will contain the lastly defined key. To obtain redefined values use ResXResourceReader explicitly and set AllowDuplicatedKeys to .
If the SafeMode property is the value of the IDictionaryEnumerator.Value property returned by the enumerator methods is a ResXDataNode instance rather than the resource value. The same applies for the return value of GetObject and GetMetaObject methods. This makes possible to check the raw .resx content before deserialization if the .resx file is from an untrusted source. See also the example at ResXDataNode.
If SafeMode property is the GetString and GetMetaString methods will not throw an InvalidOperationException even for non-string values; they return the raw XML value instead.
The following example demonstrates the behavior of SafeMode property (see the first example as well, where the entries are accessed by the enumerators).
using System;
using KGySoft.Resources;
public class Example
{
private const string resx = @"<?xml version='1.0' encoding='utf-8'?>
<root>
<data name='string'>
<value>Test string</value>
<comment>Default data type is string (when there is neither 'type' nor 'mimetype' attribute).</comment>
</data>
<data name='binary' type='System.Byte[]'>
<value>VGVzdCBieXRlcw==</value>
</data>
<data name='dangerous' mimetype='application/x-microsoft.net.object.binary.base64'>
<value>boo!</value>
<comment>BinaryFormatter will throw an exception for this invalid content.</comment>
</data>
</root>";
public static void Main()
{
// please note that default value of SafeMode is false. Nevertheless, reading the .resx containing an invalid node (dangerous)
// will not cause any problem because nothing is deserialized yet.
var set = ResXResourceSet.FromFileContents(resx); // same as "new ResXResourceSet(new StringReader(resx));"
// enabling SafeMode changes the GetObject/GetString behavior
set.SafeMode = true;
Console.WriteLine($"Return type of GetObject in safe mode: {set.GetObject("string").GetType()}");
Console.WriteLine();
Console.WriteLine("*** Demonstrating SafeMode=true ***");
TreatSafely(set, "unknown");
TreatSafely(set, "string");
TreatSafely(set, "binary");
TreatSafely(set, "dangerous");
set.SafeMode = false;
Console.WriteLine();
Console.WriteLine("*** Demonstrating SafeMode=false ***");
TreatUnsafely(set, "unknown");
TreatUnsafely(set, "string");
TreatUnsafely(set, "binary");
TreatUnsafely(set, "dangerous");
}
private static void TreatSafely(ResXResourceSet set, string resourceName)
{
// in SafeMode GetObject returns a ResXDataNode
var resource = set.GetObject(resourceName) as ResXDataNode;
if (resource == null)
{
Console.WriteLine($"Resource name '{resourceName}' does not exist in resource set or SafeMode is off.");
return;
}
if (resource.TypeName == null && resource.MimeType == null)
{
// to deserialize a node considered safe call GetValue
Console.WriteLine($"Resource with name '{resourceName}' is a string so it is safe. Its value is '{resource.GetValue()}'");
return;
}
if (resource.TypeName != null)
{
Console.WriteLine($"Resource with name '{resourceName}' is a '{resource.TypeName}'. If we trust this type we can call GetValue to deserialize it.");
}
else
{
Console.WriteLine($"Resource with name '{resourceName}' has only mime type: '{resource.MimeType}'.");
Console.WriteLine(" We cannot tell its type before we deserialize it. We can consider this entry potentially dangerous.");
}
// In SafeMode GetString(resourceName) never fails.
// resource.ValueData is similar but ValueData can be null if we allow cleanup .resx content after deserialization.
Console.WriteLine($" Raw string value: {set.GetString(resourceName)}");
}
private static void TreatUnsafely(ResXResourceSet set, string resourceName)
{
// If SafeMode is false, GetObject returns null for existing resources containing null value, too.
// Use ContainsResource to distinct non-existing and null values.
if (!set.ContainsResource(resourceName))
{
Console.WriteLine($"The resource set does not contain a resource named '{resourceName}'.");
return;
}
try
{
// If SafeMode is false, GetObject tries to deserialize the resource.
// GetString would throw an InvalidOperationException on non-string values.
var value = set.GetObject(resourceName);
Console.WriteLine($"Type of resource with name '{resourceName}' is {value?.GetType().ToString() ?? "<none>"}. String representation: {value ?? "<null>"}");
}
catch (Exception e)
{
Console.WriteLine($"Obtaining '{resourceName}' failed with an error: {e.Message}");
}
}
}
// The example displays the following output:
// Return type of GetObject in safe mode: KGySoft.Resources.ResXDataNode
//
// *** Demonstrating SafeMode=true ***
// Resource name 'unknown' does not exist in resource set or SafeMode is off.
// Resource with name 'string' is a string so it is safe. Its value is 'Test string'
// Resource with name 'binary' is a 'System.Byte[]'. If we trust this type we can call GetValue to deserialize it.
// Raw string value: VGVzdCBieXRlcw==
// Resource with name 'dangerous' has only mime type: 'application/x-microsoft.net.object.binary.base64'.
// We cannot tell its type before we deserialize it. We can consider this entry potentially dangerous.
// Raw string value: boo!
//
// *** Demonstrating SafeMode=false ***
// The resource set does not contain a resource named 'unknown'.
// Type of resource with name 'string' is System.String. String representation: Test string
// Type of resource with name 'binary' is System.Byte[]. String representation: System.Byte[]
// Obtaining 'dangerous' failed with an error: The input is not a valid Base-64 string as it contains a non-base 64 character,
// more than two padding characters, or an illegal character among the padding characters.
ResXResourceSet can load .resx files produced both by ResXResourceWriter and System.Resources.ResXResourceWriter.
Incompatibility with System.Resources.ResXResourceSet:
New features and improvements compared to System.Resources.ResXResourceSet:
ResXResourceSet(Stream, String) | Initializes a new instance of the ResXResourceSet class using the ResXResourceReader to read resources from the specified stream. |
ResXResourceSet(String, String) | Initializes a new instance of a ResXResourceSet class using the ResXResourceReader that opens and reads resources from the specified file. |
ResXResourceSet(TextReader, String) | Initializes a new instance of the ResXResourceSet class using the ResXResourceReader to read resources from the specified textReader. |
AutoFreeXmlData |
Gets or sets whether the raw XML data of the stored elements should be freed once their value has been deserialized.
Default value: . |
BasePath | Gets the base path for the relative file paths specified in a ResXFileRef object. |
CloneValues |
Gets or sets whether GetObject/GetMetaObject
and GetEnumerator/GetMetadataEnumerator methods return always a new copy of the stored values.
Default value: . |
FileName | If this ResXResourceSet has been created from a file, returns the name of the original file. This property will not change if the ResXResourceSet is saved into another file. |
IsModified | Gets whether this ResXResourceSet instance is modified (contains unsaved data). |
SafeMode |
Gets or sets whether the ResXResourceSet works in safe mode. In safe mode the retrieved
objects are not deserialized automatically.
Default value: . |
ContainsMeta | Gets whether the current ResXResourceSet contains a metadata with the given name. |
ContainsResource | Gets whether the current ResXResourceSet contains a resource with the given name. |
FromFileContents | Creates a new ResXResourceSet object and initializes it to read a string whose contents are in the form of an XML resource file. |
GetAliasEnumerator | Returns an IDictionaryEnumerator that can iterate through the aliases of the ResXResourceSet. |
GetAliasValue | Gets the assembly name for the specified alias. |
GetDefaultReader |
Returns the type of ResXResourceReader, which is the preferred resource reader class for ResXResourceSet.
(Overrides ResourceSetGetDefaultReader) |
GetDefaultWriter |
Returns the type of ResXResourceWriter, which is the preferred resource writer class for ResXResourceSet.
(Overrides ResourceSetGetDefaultWriter) |
GetEnumerator |
Returns an IDictionaryEnumerator that can iterate through the resources of the ResXResourceSet.
(Overrides ResourceSetGetEnumerator) |
GetMetadataEnumerator | Returns an IDictionaryEnumerator that can iterate through the metadata of the ResXResourceSet. |
GetMetaObject | Searches for a metadata object with the specified name. |
GetMetaString | Searches for a String metadata with the specified name. |
GetObject(String) |
Searches for a resource object with the specified name.
(Overrides ResourceSetGetObject(String)) |
GetObject(String, Boolean) |
Searches for a resource object with the specified name.
(Overrides ResourceSetGetObject(String, Boolean)) |
GetString(String) |
Searches for a String resource with the specified name.
(Overrides ResourceSetGetString(String)) |
GetString(String, Boolean) |
Searches for a String resource with the specified name.
(Overrides ResourceSetGetString(String, Boolean)) |
RemoveAliasValue | Removes an assembly alias value from the current ResXResourceSet. |
RemoveMetaObject | Removes a metadata object from the current ResXResourceSet with the specified name. |
RemoveObject | Removes a resource object from the current ResXResourceSet with the specified name. |
Save(Stream, Boolean, Boolean, String) | Saves the ResXResourceSet to the specified stream. |
Save(String, Boolean, Boolean, String) | Saves the ResXResourceSet to the specified file. |
Save(TextWriter, Boolean, Boolean, String) | Saves the ResXResourceSet by the specified textWriter. |
SetAliasValue | Adds or replaces an assembly alias value in the current ResXResourceSet. |
SetMetaObject | Adds or replaces a metadata object in the current ResXResourceSet with the specified name. |
SetObject | Adds or replaces a resource object in the current ResXResourceSet with the specified name. |
Convert |
Converts an Object specified in the obj parameter to the desired targetType.
See the Examples section of the generic ConvertTTarget(Object, CultureInfo) overload for an example. (Defined by ObjectExtensions) |
ConvertTTarget |
Converts an Object specified in the obj parameter to the desired TTarget.
(Defined by ObjectExtensions) |
In |
Gets whether item is among the elements of set.
See the Examples section of the generic InT(T, T) overload for an example. (Defined by ObjectExtensions) |
IndexOf |
Searches for an element in the source enumeration where the specified predicate returns .
(Defined by EnumerableExtensions) |
IndexOf |
Searches for an element in the source enumeration.
(Defined by EnumerableExtensions) |
IsNullOrEmpty |
Determines whether the specified source is or empty (has no elements).
(Defined by EnumerableExtensions) |
TryAdd |
Tries to add the specified item to the collection.
(Defined by EnumerableExtensions) |
TryAddRange |
Tries to add the specified collection to the target collection.
(Defined by EnumerableExtensions) |
TryClear |
Tries to remove all elements from the collection.
(Defined by EnumerableExtensions) |
TryConvert |
Tries to convert an Object specified in the obj parameter to the desired targetType.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example. (Defined by ObjectExtensions) |
TryConvert |
Tries to convert an Object specified in the obj parameter to the desired targetType.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example. (Defined by ObjectExtensions) |
TryConvertTTarget |
Tries to convert an Object specified in the obj parameter to the desired TTarget.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example. (Defined by ObjectExtensions) |
TryConvertTTarget |
Tries to convert an Object specified in the obj parameter to the desired TTarget.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example. (Defined by ObjectExtensions) |
TryGetCount |
Tries to get the number of elements in the source enumeration without enumerating it.
(Defined by EnumerableExtensions) |
TryGetElementAt |
Tries to get an item at the specified index in the collection.
(Defined by EnumerableExtensions) |
TryInsert |
Tries to insert the specified item at the specified index to the collection.
(Defined by EnumerableExtensions) |
TryInsertRange |
Tries to insert the specified collection into the target collection.
(Defined by EnumerableExtensions) |
TryRemove |
Tries to remove the specified item from to the collection.
(Defined by EnumerableExtensions) |
TryRemoveAt |
Tries to remove an item at the specified index from the collection.
(Defined by EnumerableExtensions) |
TryRemoveRange |
Tries to remove count amount of items from the specified collection at the specified index.
(Defined by EnumerableExtensions) |
TryReplaceRange |
Tries to remove count amount of items from the target at the specified index, and
to insert the specified collection at the same position. The number of elements in collection can be different from the amount of removed items.
(Defined by EnumerableExtensions) |
TrySetElementAt |
Tries to set the specified item at the specified index in the collection.
(Defined by EnumerableExtensions) |