我来自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”关键字为类或命名空间创建别名。从答案来看,似乎无法为变量创建别名。
答案 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";
但你必须有一个很好的理由这样做。