Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dictionary values by reference

Tags:

c#

In our application we have some strings coming from translation that can contain variables. For example in Can i have a {beverage}? the {beverage} part should be replaced with a variable. My current implementation works by having a Dictionary of the name and value of all variables, and just replacing the correct string. However i'd like to register the variables by reference, so that if the value is ever changed the resulting string is changed as well. Usually passing a parameter with the ref keyword would do the trick, but i'm unsure on how to store those in a Dictionary.

TranslationParser:

static class TranslationParser
{
    private const string regex = "{([a-z]+)}";
    private static Dictionary<string, object> variables = new Dictionary<string,object>();

    public static void RegisterVariable(string name, object value)
    {
        if (variables.ContainsKey(name))
            variables[name] = value;
        else
            variables.Add(name, value);
    }

    public static string ParseText(string text)
    {
        return Regex.Replace(text, regex, match =>
        {
            string varName = match.Groups[1].Value;

            if (variables.ContainsKey(varName))
                return variables[varName].ToString();
            else
                return match.Value;
        });
    }
}

main.cs

        string bev = "cola";
        TranslationParser.RegisterVariable("beverage", bev);
        //Expected: "Can i have a cola?"
        Console.WriteLine(TranslationParser.ParseText("Can i have a {beverage}?")); 
        bev = "fanta";
        //Expected: "Can i have a fanta?"
        Console.WriteLine(TranslationParser.ParseText("Can i have a {beverage}?")); 

Is this possible at all, or am i just approaching the problem incorrectly? I fear that the only solution would involve unsafe code (pointers).

So in short, i'd like to store a variable in a Dictionary, change the original variable and get the changed value from the Dictionary. Like you would do with the ref keyword.

like image 787
TJHeuvel Avatar asked Nov 05 '22 01:11

TJHeuvel


1 Answers

Another way to use wrappers. You can wrap your variables every time when you regiester them.

class ObjectWrapper
{
    private object _value;

    public ObjectWrapper(object value) 
    {
        _value = value;
    }

    public override string ToString()
    {
        return _value.ToString();
    }
}

static class TranslationParser
{
    private const string regex = "{([a-z]+)}";
    private static Dictionary<string, ObjectWrapper> variables = new Dictionary<string, ObjectWrapper>();

    public static void RegisterVariable(string name, object value)
    {
        var wrapped = new ObjectWrapper(value);
        if (variables.ContainsKey(name))
            variables[name] = wrapped;
        else
            variables.Add(name, wrapped);
    }

    public static string ParseText(string text)
    {
        return Regex.Replace(text, regex, match =>
        {
            string varName = match.Groups[1].Value;

            if (variables.ContainsKey(varName))
                return variables[varName].ToString();
            else
                return match.Value;
        });
    }
}

Edit:

But actually, I think it's impossible without unsafe code to track variables in a way that you want to do. Value-types and references to reference-type stored in stack, and if you just replace reference, it will not affect to real object in heap (reference to that object you store in the dictionary). So that you need to have references (say pointers) to stack memory.

Edit again: I was wrong!

It is possible to track any varaible using expressions:

class Wrapper
{
    private readonly Dictionary<string, MemberExpression> _registrations = 
        new Dictionary<string, MemberExpression>();

    public void Register<T>(string name, Expression<Func<T>> expr)
    {
        _registrations[name] = (MemberExpression)expr.Body;
    }

    public object GetValue(string name)
    {
        var expr = _registrations[name];
        var fieldInfo = (FieldInfo)expr.Member;
        var obj = ((ConstantExpression)expr.Expression).Value;
        return fieldInfo.GetValue(obj);
    }
}
private static void Main(string[] args)
{
    var wrapper = new Wrapper();
    int x = 0;
    storage.Register("x", () => x);
    Console.WriteLine(wrapper.GetValue("x")); //0
    x = 1;
    Console.WriteLine(wrapper.GetValue("x")); //1
}
like image 126
tukaef Avatar answered Nov 09 '22 06:11

tukaef