Search code examples
c#objectdictionaryreference

Store reference to an object in dictionary


I have been searching for a way to save the references of variables of various types into a dictionary, together with a corresponding key. Then i would like to modify the instance of the variable by accessing its reference through the dictionary by its key. For storing the references, i tried to use <object>, but without success. Neither Dictionaries nor Lists accept anything like Dictionary<string, ref int>. The following code compiles, but seems to update the variables by value only. Any ideas or workarounds?

Here's the (tested) code:

class Test1
{
    IDictionary<string, object> MyDict = new Dictionary<string, object>();

    public void saveVar(string key, ref int v) //storing the ref to an int
    {
        MyDict.Add(key, v);
    }
    public void saveVar(string key, ref string s) //storing the ref to a string
    {
        MyDict.Add(key, s);
    }

    public void changeVar(string key) //changing any of them
    {
        if(MyDict.GetType() == typeof(int))
        {
            MyDict[key] = (int)MyDict[key] * 2;
        }
        if(MyDict.GetType() == typeof(string))
        {
            MyDict[key] = "Hello";
        }
    }
}

And this is how i call the methods of the class

Test1 t1 = new Test1();
int myInt = 3;
string myString = "defaultString";

Console.WriteLine(myInt); //returns "3"
Console.WriteLine(myString); //returns "defaultString"

t1.saveVar("key1", ref myInt);
t1.saveVar("key2", ref myString);

t1.changeVar("key1");
t1.changeVar("key2");

Console.WriteLine(myInt); //should return "6"
Console.WriteLine(myString); //should return "Hello"

Solution

  • The best solution I can think of for this is to store delegates in the dictionary that will allow you to retrieve and modify the variables.

    Let’s start by declaring a type that contains a getter and a setter delegate:

    sealed class VariableReference
    {
        public Func<object> Get { get; private set; }
        public Action<object> Set { get; private set; }
        public VariableReference(Func<object> getter, Action<object> setter)
        {
            Get = getter;
            Set = setter;
        }
    }
    

    The dictionary would have the type:

    Dictionary<string, VariableReference>
    

    To store a variable, say foo of type string, in the dictionary, you’d write the following:

    myDic.Add(key, new VariableReference(
        () => foo,                      // getter
        val => { foo = (string) val; }  // setter
    ));
    

    To retrieve the value of a variable, you’d write

    var value = myDic[key].Get();
    

    To change the value of a variable to newValue, you’d write

    myDic[key].Set(newValue);
    

    This way, the variable that you’re changing is genuinely the original variable foo, and foo can be anything (a local variable, a parameter, a field on an object, a static field... even a property).

    Putting this all together, this is what the class Test1 would look like:

    class Test1
    {
        Dictionary<string, VariableReference> MyDict = new Dictionary<string, VariableReference>();
    
        public void saveVar(string key, Func<object> getter, Action<object> setter)
        {
            MyDict.Add(key, new VariableReference(getter, setter));
        }
    
        public void changeVar(string key) // changing any of them
        {
            if (MyDict[key].Get() is int)
            {
                MyDict[key].Set((int)MyDict[key].Get() * 2);
            }
            else if (MyDict[key].Get() is string)
            {
                MyDict[key].Set("Hello");
            }
        }
    }
    
    // ...
    
    Test1 t1 = new Test1();
    int myInt = 3;
    string myString = "defaultString";
    
    Console.WriteLine(myInt);    // prints "3"
    Console.WriteLine(myString); // prints "defaultString"
    
    t1.saveVar("key1", () => myInt, v => { myInt = (int) v; });
    t1.saveVar("key2", () => myString, v => { myString = (string) v; });
    
    t1.changeVar("key1");
    t1.changeVar("key2");
    
    Console.WriteLine(myInt);    // actually prints "6"
    Console.WriteLine(myString); // actually prints "Hello"