我一直在寻找一种方法,将各种类型的变量的引用与相应的密钥一起保存到字典中。然后我想通过其键通过字典访问它的引用来修改变量的实例。
为了存储引用,我尝试使用<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"
答案 0 :(得分:6)
我能想到的最佳解决方案是将代理存储在字典中,以便您检索和修改变量。
让我们首先声明一个包含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"
答案 1 :(得分:0)
除了Kevin指出的问题,你需要将你的值类型包装在某种引用类型中。
正如您所知,问题是泛型类型不能与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
}
}
答案 2 :(得分:-1)
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";
}
}
}
由于您现在正在改变调用者也有引用的引用类型,因此可以观察到其值的更改。