I want to be able to retrieve a language dependent string during runtime, why I created the class below. It let's me get the value in the preferred language whenever I want with getValue():
internal class ResourceString : IResourceString
{
public ResourceString(string id, ResourceManager rm, params IResourceString[] parameters)
{
Id = id;
Rm = rm;
m_Parameters = parameters ?? Array.Empty<IResourceString>();
}
public string Id { get; }
private ResourceManager Rm { get; }
private readonly IResourceString[] m_Parameters;
public string GetValue(CultureInfo cultureInfo)
{
if (m_Parameters.Count() > 0)
{
return string.Format(Rm.GetString(Id, cultureInfo), m_Parameters.Select(p => p.GetValue(cultureInfo)));
}
else
{
return Rm.GetString(Id, cultureInfo);
}
}
};
//Extension to get a specific value downstream
internal static class MlExtension
{
public static string GetValue(this IResourceString source)
{
return source.GetValue(CultureInfo.CurrentCulture);
}
}
Problem with that is, when creating the ResourceString, you have to pass the key of the Resource file (using nameof()) as a string, named id here, which is easily overlooked:
correct:
new ResourceString(nameof(Guid.Rule_Name), Guid.ResourceManager)
not correct:
new ResourceString(Guid.Rule_Name, Guid.ResourceManager)
Is there a smart way to somehow indicate, that the key has to be passed, not the value, or even force it?
CodePudding user response:
I used a generic type parameter ResourceString
to make sure that the type of the key passed to the constructor is always a string.
I've implemented the fix to your code, as seen here. Hope this is what you're looking for, if not criticize me.
internal class ResourceString<T> : IResourceString where T : class
{
public ResourceString(T key, ResourceManager rm, params IResourceString[] parameters)
{
Key = key;
Rm = rm;
m_Parameters = parameters ?? Array.Empty<IResourceString>();
}
public T Key { get; }
private ResourceManager Rm { get; }
private readonly IResourceString[] m_Parameters;
public string GetValue(CultureInfo cultureInfo)
{
if (m_Parameters.Count() > 0)
{
return string.Format(Rm.GetString((string)Key, cultureInfo), m_Parameters.Select(p => p.GetValue(cultureInfo)));
}
else
{
return Rm.GetString((string)Key, cultureInfo);
}
}
}
internal static class MlExtension
{
public static string GetValue<T>(this ResourceString<T> source) where T : class
{
return source.GetValue(CultureInfo.CurrentCulture);
}
}
const string RULE_NAME_KEY = "Rule_Name";
// ...
new ResourceString<string>(RULE_NAME_KEY, Guid.ResourceManager)
// or
new ResourceString<string>(nameof(Guid.Rule_Name), Guid.ResourceManager)
CodePudding user response:
Assuming that the keys are always the names of public static string properties in some class, you could use the follwoing technique:
Instead if pasing the Id as string, pass it as System.Linq.Expressions.Expression and derive the name of the property from it.
public ResourceString(Expression<Func<string>> expression)
{
Id = PropertyNameFromExpression(expression);
}
// Helper methods:
private static string PropertyNameFromExpression<T>(Expression<Func<T>> expression)
{
return PropertyNameFromExpression(expression.Body);
}
private static string PropertyNameFromExpression(Expression expression)
{
return ((MemberExpression)expression).Member.Name;
}
Usage:
new ResourceString(() => Guid.Rule_Name);
This might imply some runtime performance penalty, however.