C#在创建字符串后更改字符串

C#在创建字符串后更改字符串,c#,immutability,C#,Immutability,好吧,我知道这个问题非常简单,我承认我对C#也是个新手。但标题并不能描述整个情况,所以请听我说 我需要修改一个URL字符串,该字符串是在C#代码隐藏中创建的,从字符串末尾删除子字符串“.aspx”。所以基本上我知道我的URL,进入这个类,将类似于“Blah.aspx”,我想去掉字符串中的“.aspx”部分。我认为这是很容易做到的,只要找到子字符串,并删除它,如果它存在的话(或一些类似的策略,如果有人有一个优雅的解决方案,如果他们以前认为做过的话,会很感激)。问题是: “因为字符串是不可变的,所以

好吧,我知道这个问题非常简单,我承认我对C#也是个新手。但标题并不能描述整个情况,所以请听我说

我需要修改一个URL字符串,该字符串是在C#代码隐藏中创建的,从字符串末尾删除子字符串“.aspx”。所以基本上我知道我的URL,进入这个类,将类似于“Blah.aspx”,我想去掉字符串中的“.aspx”部分。我认为这是很容易做到的,只要找到子字符串,并删除它,如果它存在的话(或一些类似的策略,如果有人有一个优雅的解决方案,如果他们以前认为做过的话,会很感激)。问题是:


“因为字符串是不可变的,所以在创建字符串对象后(如果不使用不安全的代码),不可能修改字符串对象的值。”这是来自MSDN官方网站。所以我现在想知道,如果字符串真的是不可变的,那么我就不能(不应该)在创建字符串之后更改它。那么,我如何确保我计划做的事情是安全的呢?

字符串不变性对于正常使用来说不是问题——它只是意味着像“Replace”这样的成员函数,而不是修改现有的字符串对象,而是返回一个新的字符串对象。实际上,这通常意味着您必须记住将更改复制回原始版本,例如:

string x = "Blah.aspx";
x.Replace(".aspx", "");       // still "Blah.aspx"
x = x.Replace(".aspx", "");   // now "Blah"
字符串的奇怪之处在于
System.String
继承了
System.Object
,但由于其不变性,其行为类似于值类型而不是对象。例如,如果将字符串传递到函数中,则无法修改它,除非通过引用传递:

void Test(string y)
{
    y = "bar";
}
void Test(ref string z)
{
    z = "baz";
}
string x = "foo";
Test(x);                 // x is still "foo"
Test(ref x);             // x is now "baz"

你不改变字符串,你改变变量。与引用字符串(如
“foo.aspx”
)的变量不同,将其更改为指向值为
“foo”
的新字符串

打个比方,在数字2上加一并不会改变数字2。两个仍然和以前一样,您已经将一个变量从一个数字改为另一个数字

对于您的具体情况,
EndsWith
Remove
使其变得足够简单:

if (url.EndsWith(".aspx"))
    url = url.Remove(url.Length - ".aspx".Length);
请注意,
Remove
取一个字符串,一个整数,并给我们一个全新的字符串,我们需要将它赋回变量。它不会改变字符串本身

还请注意,有一个类可用于解析URL,它将能够处理可能出现的所有复杂情况,包括哈希、查询参数等。您应该使用该类解析出您感兴趣的URL的各个方面。

String.Replace()
不会修改字符串。它将创建一个新的。因此,以下代码:

String myUrl = @"http://mypath.aspx";
String withoutExtension = myUrl.Replace(".aspx", "");
将创建一个全新的字符串,该字符串被分配给withoutExtension。

C#中的
字符串是不可变的,正如您所说。这意味着这将在内存中创建多个
字符串
对象:

String s = "String of numbers 0";
s += "1";
s += "2";
因此,虽然变量
s
将返回数值012
字符串,但在内部它需要在内存中创建三个字符串来完成

在您的特定情况下,解决方案非常简单:

String myPath = "C:\\folder1\\folder2\\myFile.aspx";
myPath = Path.Combine(Path.GetDirectoryName(myPath), Path.GetFileNameWithoutExtension(myPath));
同样,这看起来好像
myPath
已经改变了,但实际上没有改变。发生了内部复制和分配,您可以继续使用相同的变量

此外,如果必须保留原始变量,只需创建一个新变量:

String myPath = "C:\\folder1\\folder2\\myFile.aspx";
String thePath = Path.Combine(Path.GetDirectoryName(myPath), Path.GetFileNameWithoutExtension(myPath));
无论哪种方式,最终都会得到一个可以使用的变量


请注意,使用
Path
方法可确保获得正确的路径操作,而不是盲目的
String
替换,这可能会产生意外的副作用。

您不能更改字符串(也不应该更改)。但是您可以轻松地在旧字符串的基础上创建新字符串。调用
子字符串时,会为您创建一个新字符串。如果它是“Blah.aspx?query=yup”,结果应该是什么?不幸的是,我刚刚发现该字符串是在离开此类后添加的.aspx。。。所以现在我再一次被困在寻找发生这种情况的地方。我的问题是我使URL看起来像“Blah?ID=100.aspx”,这是不正确的。如果您想对字符串进行大量操作,最好使用一个可变的
StringBuilder
。这样可以避免为每个插入/替换操作生成新字符串。在您的情况下,
Uri
/
UriBuilder
类可能很有用。@mikez这对于小操作来说可能过于昂贵。不管怎么说,复制仍在进行。OP似乎只想在末尾删除它,而不是在任何地方删除它。@Servy在这种情况下,您可以使用正则表达式指定.aspx之后没有任何内容。“.aspx$”就可以了。@KyleRogers你可以,如果你想的话,但那是用大锤打苍蝇。这实际上是我所需要的,所以我选择了这个作为答案。对于下面的内容,我仍将研究各位所说的内容,并感谢各位的评论。
String
在任何意义上都不像值类型。它是一种引用类型,在所有情况下的行为都类似于引用类型(因为它就是这样)。不变性与值/引用类型无关。值类型可以是可变的,也可以是不可变的,引用类型可以是可变的,也可以是不可变的。不要忘记,如果您在发布后意识到另一个答案(更好或相同)已经发布,那么删除您的帖子就不需要花费任何成本,以避免问题与答案混杂在一起而没有添加任何内容。