Created
March 3, 2020 11:21
-
-
Save PedroMGMendes/ffde0af9feed7a18960d28f18a5f9a0d to your computer and use it in GitHub Desktop.
C# custom ResourceManager loader for usage with ILRepack.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Globalization; | |
using System.Reflection; | |
using System.Resources; | |
namespace ILRepack | |
{ | |
/// <summary> | |
/// SingleAssembly Resource Manager. | |
/// </summary> | |
/// <seealso cref="System.Resources.ResourceManager" /> | |
public class SingleAssemblyResourceManager : ResourceManager | |
{ | |
private Dictionary<string, ResourceSet> singleAssemblyResourceSets; | |
private string[] singleAssemblyResouceNames; | |
/// <summary> | |
/// Initializes a new instance of the <see cref="SingleAssemblyResourceManager" /> class. | |
/// </summary> | |
/// <param name="baseName">The root name of the resource file without its extension but including any fully qualified namespace name. For example, the root name for the resource file named MyApplication.MyResource.en-US.resources is MyApplication.MyResource.</param> | |
/// <param name="assembly">The main assembly for the resources.</param> | |
public SingleAssemblyResourceManager(string baseName, Assembly assembly) | |
: base(baseName, assembly) | |
{ | |
this.singleAssemblyResourceSets = new Dictionary<string, ResourceSet>(); | |
this.singleAssemblyResouceNames = this.MainAssembly.GetManifestResourceNames(); | |
} | |
/// <summary> | |
/// Internals the get resource set. | |
/// </summary> | |
/// <param name="culture">The culture.</param> | |
/// <param name="createIfNotExists">if set to <c>true</c> [create if not exists].</param> | |
/// <param name="tryParents">if set to <c>true</c> [try parents].</param> | |
/// <returns>sample jk.</returns> | |
protected override ResourceSet InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents) | |
{ | |
// intentional behaviour always try to fallback to parent cultures | |
while (culture != null && culture != CultureInfo.InvariantCulture) | |
{ | |
// Look in the Single Assembly ResourceSet table | |
Dictionary<string, ResourceSet> localResourceSets = this.singleAssemblyResourceSets; | |
ResourceSet rs = null; | |
if (localResourceSets != null) | |
{ | |
lock (localResourceSets) | |
{ | |
localResourceSets.TryGetValue(culture.Name, out rs); | |
} | |
} | |
if (rs != null) | |
{ | |
return rs; | |
} | |
var cultureNameResource = this.FindResourceNameIgnoreCase(this.BaseName + "." + culture.Name + ".resources"); | |
if (!string.IsNullOrWhiteSpace(cultureNameResource)) | |
{ | |
var resourceStream = this.MainAssembly.GetManifestResourceStream(cultureNameResource); | |
if (resourceStream != null) | |
{ | |
rs = new ResourceSet(resourceStream); | |
AddResourceSet(localResourceSets, culture.Name, ref rs); | |
return rs; | |
} | |
} | |
culture = culture.Parent; | |
} | |
var resSet = base.InternalGetResourceSet(culture, createIfNotExists, tryParents); | |
return resSet; | |
} | |
// Simple helper to ease maintenance and improve readability. | |
private string FindResourceNameIgnoreCase(string resourceName) | |
{ | |
foreach (var item in this.singleAssemblyResouceNames) | |
{ | |
if (item.Equals(resourceName, StringComparison.OrdinalIgnoreCase)) | |
{ | |
return item; | |
} | |
} | |
return string.Empty; | |
} | |
// Simple helper to ease maintenance and improve readability. | |
private static void AddResourceSet(Dictionary<string, ResourceSet> localResourceSets, string cultureName, ref ResourceSet rs) | |
{ | |
// InternalGetResourceSet is both recursive and reentrant - | |
// assembly load callbacks in particular are a way we can call | |
// back into the ResourceManager in unexpectedly on the same thread. | |
lock (localResourceSets) | |
{ | |
// If another thread added this culture, return that. | |
ResourceSet lostRace; | |
if (localResourceSets.TryGetValue(cultureName, out lostRace)) | |
{ | |
if (!object.ReferenceEquals(lostRace, rs)) | |
{ | |
// Note: In certain cases, we can be trying to add a ResourceSet for multiple | |
// cultures on one thread, while a second thread added another ResourceSet for one | |
// of those cultures. If there is a race condition we must make sure our ResourceSet | |
// isn't in our dictionary before closing it. | |
if (!localResourceSets.ContainsValue(rs)) | |
{ | |
rs.Dispose(); | |
} | |
rs = lostRace; | |
} | |
} | |
else | |
{ | |
localResourceSets.Add(cultureName, rs); | |
} | |
} | |
} | |
/// <summary> | |
/// Tells the resource manager to call the <see cref="M:System.Resources.ResourceSet.Close"></see> method on all <see cref="T:System.Resources.ResourceSet"></see> objects and release all resources. | |
/// </summary> | |
public override void ReleaseAllResources() | |
{ | |
base.ReleaseAllResources(); | |
Dictionary<string, ResourceSet> localResourceSets = this.singleAssemblyResourceSets; | |
// If any calls to Close throw, at least leave ourselves in a | |
// consistent state. | |
this.singleAssemblyResourceSets = new Dictionary<string, ResourceSet>(); | |
lock (localResourceSets) | |
{ | |
foreach (var item in localResourceSets) | |
{ | |
item.Value.Close(); | |
} | |
} | |
} | |
/// <summary> | |
/// Returns the value of the string resource localized for the specified culture. | |
/// </summary> | |
/// <param name="name">The name of the resource to retrieve.</param> | |
/// <param name="culture">An object that represents the culture for which the resource is localized.</param> | |
/// <returns> | |
/// The value of the resource localized for the specified culture, or null if <paramref name="name">name</paramref> cannot be found in a resource set. | |
/// </returns> | |
public override string GetString(string name, CultureInfo culture) | |
{ | |
return base.GetString(name, culture); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment