Home > Back-end >  Is is possible to force passing the key of a resource file entry, not the value?
Is is possible to force passing the key of a resource file entry, not the value?

Time:01-08

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?


Part of a resource file: enter image description here

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.

  • Related