将参考存储在字典中

我一直在寻找一种方法将各种类型的变量的引用保存到字典中,并与相应的键一起保存。 然后,我想修改变量的实例,通过字典的键来访问它的引用。 为了存储引用,我试图使用<object> ,但没有成功。 字典和列表都不能接受Dictionary<string, ref int> 。 下面的代码编译,但似乎只通过值更新变量。 任何想法或解决方法?

这是(测试)代码:

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";
        }
    }
}

这就是我称之为课堂的方法

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"

我能想到的最佳解决方案是将代理存储在字典中,以便您可以检索和修改变量。

我们首先声明一个包含getter和setter委托的类型:

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;
    }
}

该字典将具有以下类型:

Dictionary<string, VariableReference>

为了在字典中存储一个变量,比如foo类型的string ,你可以写下如下代码:

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

要检索一个变量的值,你会写

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

要改变一个变量的值为newValue ,你会写

myDic[key].Set(newValue);

这样,你改变的变量真的是原始变量foo ,而foo可以是任何东西(一个局部变量,一个参数,一个对象上的字段,一个静态字段,甚至一个属性)。

综合起来,这就是类Test1样子:

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"

ref参数的引用不能离开调用它的方法的范围。 这是因为在方法调用完成后,作为引用的变量不能保证在范围内。 您需要使用ref以外的工具创建一个间接层,以允许调用者使用的变量进行变异。

尽管这样做很容易。 你只需要一个带有可变成员的类:

public class Pointer
{
    public object Value { get; set; }
}

你现在可以写:

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

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

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

由于您现在正在改变调用方也有参考的参考类型,因此他们可以观察其值的变化。


除了凯文指出的问题外,你需要用某种引用类型来包装你的值类型。

正如你所想的那样,问题在于泛型类型不能与ref关键字一起工作,并且当你在你的字典中分配一个新的值类型时,它将用一个不同的引用替换引用,而不是更新它。 一旦将它分配给字典,就没有办法保留ref语义。

但是,你可以做的就是这样,只需将值类型包装为引用类型即可:

public class MyRef<T> {
    public T Ref {get;set;}
}

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

    public void saveVar(string key, object v) 
    {
        MyDict.Add(key, v);
    }

    public void changeVar(string key, object newValue) //changing any of them
    {
        var ref1 = MyDict[key] as MyRef<int>;
        if (ref1 != null) {
            ref1.Ref = (int)newValue;
            return; // no sense in wasting cpu cycles
        }

        var ref2 = MyDict[key] as MyRef<string>;
        if (ref2 != null) {
            ref2.Ref = newValue.ToString();
        }
    }

    public void DoIt()
    {
        var v = new MyRef<int> { Ref = 1 };

        saveVar("First", v);
        changeVar("First", 2);

        Console.WriteLine(v.Ref.ToString()); // Should print 2
        Console.WriteLine(((MyRef<int>)MyDict["First"]).Ref.ToString()); // should also print 2
    }
}
链接地址: http://www.djcxy.com/p/21161.html

上一篇: Store reference to an object in dictionary

下一篇: How can I detect a palindrome in Hebrew?