如何传递一个对象而不是它的值

时间:2013-11-20 02:05:05

标签: c#

我正在尝试创建一个简单的解析器,其中包含我想要分配给变量的键值对。我想将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);
    }
}

4 个答案:

答案 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);
    }
}