我正在尝试创建一个简单的解析器,其中包含我想要分配给变量的键值对。我想将String映射到变量。 我认为下面的测试类应该表达我想做的事情。但是如何存储变量以便我可以更新它呢?
[TestClass]
public class StringObjectMapperTest
{
[TestMethod]
public void TestMethod1()
{
string string1 = "";
string string2 = "";
StringObjectMapper mapper = new StringObjectMapper();
mapper.Add("STRING1", ref string1);
mapper.Add("STRING2", ref string2);
mapper.Set("STRING1", "text1");
Assert.AreEqual("text1", string1); // FAILS as string1 is still ""
}
}
public class StringObjectMapper
{
private Dictionary<string, string> mapping = new Dictionary<string, string>();
public StringObjectMapper()
{
}
public void Set(string key, string value)
{
string obj = mapping[key];
obj = value;
}
internal void Add(string p, ref string string1)
{
mapping.Add(p, string1);
}
}
更新: 我试图使用盒装字符串,但这似乎也像一个不可变对象,任何想法为什么?
[TestClass]
public class StringObjectMapperTest
{
[TestMethod]
public void TestMethod1()
{
BoxedString string1 = "string1";
BoxedString string2 = "string2";
StringObjectMapper mapper = new StringObjectMapper();
mapper.Add("STRING1", ref string1);
mapper.Add("STRING2", ref string2);
mapper.Set("STRING1", "text1");
string s = string1;
Assert.AreEqual("text1", s); // Fails as s = "string1" ???
}
}
public struct BoxedString
{
private string _value;
public BoxedString(string value)
{
_value = value;
}
public void Set(string value)
{
_value = value;
}
static public implicit operator BoxedString(string value)
{
return new BoxedString(value);
}
static public implicit operator string(BoxedString boxedString)
{
return boxedString._value;
}
}
public class StringObjectMapper
{
private Dictionary<string, BoxedString> mapping = new Dictionary<string, BoxedString>();
public StringObjectMapper()
{
}
public void Set(string key, string value)
{
BoxedString obj = mapping[key];
obj.Set(value);
}
internal void Add(string p, ref BoxedString obj)
{
mapping.Add(p, obj);
}
}
答案 0 :(得分:4)
由于字符串是不可变的,所以不能这样做。更改字符串将返回新字符串。即使您在Add
中通过引用传递字符串,字典中存储的字符串值仍然是不可变的。以下是Set
中发生的事情:
public void Set(string key, string value)
{
string obj = mapping[key]; // obj points to the string value at mapping[key]
obj = value; // obj points to the string value referenced by value - mapping[key] is unchanged.
}
要执行您想要的操作,您需要使用真正的引用类型“封装”字符串 - 无论是object
还是将string
包装为Dictionary's
值的类类型。
答案 1 :(得分:3)
这不是你想要的,但这项工作......如果你接受它: - )
使用StringBuilder
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
StringBuilder string1 = new StringBuilder();
StringBuilder string2 = new StringBuilder();
StringObjectMapper mapper = new StringObjectMapper();
mapper.Add("STRING1", ref string1);
mapper.Add("STRING2", ref string2);
mapper.Set("STRING1", "text1");
Console.Write("text1" == string1.ToString());
Console.ReadKey();
}
}
public class StringObjectMapper
{
private Dictionary<string, StringBuilder> mapping = new Dictionary<string, StringBuilder>();
public StringObjectMapper()
{
}
public void Set(string key, string value)
{
StringBuilder obj = mapping[key];
obj.Clear();
obj.Append(value);
}
internal void Add(string p, ref StringBuilder string1)
{
mapping.Add(p, string1);
}
}
}
答案 2 :(得分:2)
我首先想到的是,如果没有获得ref string string1
代表的指针,这在C#中是不可能的。不幸的是,.NET被垃圾收集,这意味着指针可以改变,除非你使用fixed
块。
我认为这里更好的方法是使用一个代表方式来设置字符串的接口。
public interface IData
{
void Set(string data);
}
public class StringObjectMapper
{
private readonly Dictionary<string, IData> mapping = new Dictionary<string, IData>();
public void Set(string key, string value)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
if (value == null)
{
throw new ArgumentNullException("value");
}
mapping[key].Set(value);
}
internal void Add(string key, IData data)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
if (data == null)
{
throw new ArgumentNullException("data");
}
mapping.Add(key, data);
}
}
答案 3 :(得分:1)
我想解决这个问题的最佳方法是使用委托。虽然语法对我来说仍然有点奇怪,但它似乎是解决这个问题最简洁的方法。以下代码有效:
[TestClass]
public class StringObjectMapperTest
{
private Dictionary<string, Setter> mapping = new Dictionary<string, Setter>();
public delegate void Setter(string v);
[TestMethod]
public void TestMethod1()
{
string string1 = "string1";
string string2 = "string2";
string text1 = "text1";
string text2 = "text2";
Add("STRING1", x => string1 = x);
Add("STRING2", x => string2 = x);
Assert.AreNotEqual(text1, string1);
Set("STRING1", text1);
Assert.AreEqual(text1, string1);
Assert.AreNotEqual(text2, string2);
Set("STRING2", text2);
Assert.AreEqual(text2, string2);
}
private void Set(string key, string value)
{
Setter set = mapping[key];
set(value);
}
private void Add(string p, Setter del)
{
mapping.Add(p, del);
}
}