获取一个字符串以引用C#中的另一个

时间:2014-05-20 10:57:32

标签: c# string

我来自C ++背景。之前已经问过这个问题,但试着尽可能找不到答案。假设我有:

string[] ArrayOfReallyVeryLongStringNames = new string[500];
ArrayOfReallyVeryLongStringNames[439] = "Hello world!";

我可以创建一个引用上述字符串的字符串(这些字符串都不会编译):

string a = ref ArrayOfReallyVeryLongStringNames[439];  // no compile
string a = &ArrayOfReallyVeryLongStringNames[439];     // no compile

我明白字符串在C#中是不可变的。我也明白你无法获得托管对象的地址。

我想这样做:

a = "Donkey Kong";  // Now ArrayOfReallyVeryLongStringNames[439] = "Donkey Kong";

我已阅读Stack Overflow问题 Make a reference to another string in C# 这有一个很好的答案,但问题略有不同。我不想通过引用将此参数传递给函数。我知道如何使用“ref”关键字通过引用传递参数。

如果答案是“您无法在C#中执行此操作”,是否有方便的解决方法?

编辑: 一些答案表明问题不明确。让我们以不同的方式问它。假设我需要操纵原始长命名数组中具有主要索引的所有项目。我想在Array ... [2],Array ... [3],Array ... [5]等中添加别名到列表中。然后,使用“for”循环修改列表中的项目(可能通过将刚刚创建的列表传递给函数)。

在C#中,“using”关键字为类或命名空间创建别名。从答案来看,似乎无法为变量创建别名。

8 个答案:

答案 0 :(得分:12)

您可以创建一个包装器来保存对底层数组的引用和字符串的索引:

public sealed class ArrayStringReference
{
    private readonly string[] _array;
    private readonly int      _index;

    public ArrayStringReference(string[] array, int index)
    {
        _array = array;
        _index = index;
    }

    public string Value
    {
        get
        {
            return _array[_index];
        }

        set
        {
            _array[_index] = value;
        }
    }

    public override string ToString()
    {
        return Value;
    }
}

然后这将起作用:

    string[] ArrayOfReallyVeryLongStringNames = new string[500];
    ArrayOfReallyVeryLongStringNames[439] = "Hello world!";

    var strRef = new ArrayStringReference(ArrayOfReallyVeryLongStringNames, 439);
    Console.WriteLine(ArrayOfReallyVeryLongStringNames[439]); // Outputs "Hello world!"
    strRef.Value = "Donkey Kong";
    Console.WriteLine(ArrayOfReallyVeryLongStringNames[439]); // Outputs "Donkey Kong"

通过提供隐式字符串运算符,您可以更方便地使用它,因此您不必使用.Value来访问基础字符串:

// Add this to class ArrayStringReference implementation

public static implicit operator string(ArrayStringReference strRef)
{
    return strRef.Value;
}

然后不必像这样访问底层字符串:

strRef.Value = "Donkey Kong";
...
string someString = strRef.Value;

你可以这样做:

strRef.Value = "Donkey Kong";
...
string someString = strRef; // Don't need .Value

这只是语法糖,但它可能会更容易在现有代码中开始使用ArrayStringReference。 (请注意,您仍需要使用.Value 设置基础字符串。)

答案 1 :(得分:5)

你能得到的最接近的是:

unsafe
{
    string* a = &ArrayOfReallyVeryLongStringNames[439];     // no compile
}

哪个例外:

  

无法获取地址,获取大小或声明指向托管类型的指针('字符串')

所以不,不可能......

另请阅读此MSDN article,其中说明了可以使用哪些类型(blittable类型)。

答案 2 :(得分:2)

当我在C#中做这样的事情时:

string a = "String 1";
string b = a;
a = "String 2";

Console.WriteLine(a); // String 2
Console.WriteLine(b); // String 1

事情是,"字符串1"和"字符串2"文字是在程序开始时创建的,字符串总是指针:首先是引用"字符串1"文字和之后它引用"字符串2"。如果你希望他们总是引用相同的东西,在C#中你只需使用相同的变量。

The string objects themselves are immutable in C#

  

因为字符串"修改"实际上是一个新的字符串创建,在创建对字符串的引用时必须小心。如果您创建对字符串的引用,然后"修改"原始字符串,引用将继续指向原始对象,而不是在修改字符串时创建的新对象。

当需要字符串可变性时,例如,为了更快地连接大量字符串,使用其他类,如StringBuilder

总结一下,你想要做的事情是不可能的。

答案 3 :(得分:2)

在C#中,String是一个Object。因此String a = "Donkey Kong"表示a现在引用了正在内存中分配的字符串。那么你需要做的就是:

ArrayOfReallyVeryLongStringNames[439] = a;

这会将refrence(你应该在C#中考虑过)复制到字符串中的位置。

BUT !!当您执行a="new string";时,a将获得新的参考。看看我做的例子: http://prntscr.com/3kw18v

您只能使用不安全模式执行此操作。

答案 4 :(得分:1)

你可以创建一个包装器

public class StringWrapper
{
    public string Value {get;set;}
}

StringWrapper[] arrayOfWrappers = new StringWrapper[500];
arrayOfWrappers[439] = new StringWrapper { Value = "Hello World" };
StringWrapper a = arrayOfWrappers[439];
a.Value = "New Value";

答案 5 :(得分:1)

你想要做的是在C#中普遍气馁和积极阻止,其中逻辑应独立于内存模型,但是,请参阅相关的SO问题C# memory address and variable以获取一些信息。

编辑1

对C#中的实际问题采用更规范的方法是:

        // using System.Linq;

        string[] raw = new string[] { "alpha", "beta", "gamma", "delta" };

        List<int> evenIndices = Enumerable.Range(0, raw.Length)
            .Where(x => x % 2 == 0)
            .ToList();

        foreach (int x in evenIndices)
            raw[x] = raw[x] + " (even)";

        foreach (string x in raw)
            Console.WriteLine(x);

        /*
        OUTPUT: 

        alpha (even)
        beta
        gamma (even)
        delta
        */

如果您真的想要修改原始内存结构本身,那么C ++可能是解决方案的更合适的语言选择。

编辑2

环顾四周,您可能希望将这个答案Hidden Features of C#?看作一个无关的问题。

答案 6 :(得分:0)

        [TestMethod]
    public void TestMethod1()
    {
        string[] arrayOfString = new string[500];
        arrayOfString[499] = "Four Ninty Nine";
        Console.WriteLine("Before Modification : {0} " , arrayOfString[499]);

        string a = arrayOfString[499];

        ModifyString(out arrayOfString[499]);

        Console.WriteLine("after a : {0}", a);
        Console.WriteLine("after arrayOfString [499]: {0}", arrayOfString[499]);

    }

    private void ModifyString(out string arrayItem)
    {
        arrayItem = "Five Hundred less one";
    }

答案 7 :(得分:0)

当然可以,呵呵:

var a = __makeref(array[666]);
__refvalue(a, string) = "hello";

但你必须有一个很好的理由这样做。