如何证明C#中字符串的不可变性?
在我上次的c#采访中,如何证明C#中字符串的不可变性?,c#,string,immutability,C#,String,Immutability,在我上次的c#采访中,我被要求证明c#string的不变性,我知道什么是c#string的不变性,但有可能通过代码证明c#string的不变性吗?请给我一个示例代码片段。 提前感谢是的,可以使用ObjectiveGenerator类来证明c#字符串的不变性。 下面的答案摘自dotmob在C#中的一篇文章 实际上,ObjutDebug将为我们在程序中创建的实例返回一个唯一的整数值。在这个类的帮助下,我们可以检查是否为String和String BuueLead中的各种操作创建了新的实例。 usin
我被要求证明c#string的不变性,我知道什么是c#string的不变性,但有可能通过代码证明c#string的不变性吗?请给我一个示例代码片段。
提前感谢是的,可以使用
ObjectiveGenerator
类来证明c#字符串的不变性。下面的答案摘自dotmob在C#中的一篇文章
实际上,ObjutDebug将为我们在程序中创建的实例返回一个唯一的整数值。在这个类的帮助下,我们可以检查是否为String和String BuueLead中的各种操作创建了新的实例。
using System;
using System.Text;
using System.Runtime.Serialization;
class Program
{
static void Main(string[] args)
{
ObjectIDGenerator idGenerator = new ObjectIDGenerator();
bool blStatus = new bool();
//just ignore this blStatus Now.
String str = "My first string was ";
Console.WriteLine("str = {0}", str);
Console.WriteLine("Instance Id : {0}", idGenerator.GetId(str, out blStatus));
//here blStatus get True for new instace otherwise it will be false
Console.WriteLine("this instance is new : {0}\n", blStatus);
str += "Hello World";
Console.WriteLine("str = {0}", str);
Console.WriteLine("Instance Id : {0}", idGenerator.GetId(str, out blStatus));
Console.WriteLine("this instance is new : {0}\n", blStatus);
//Now str="My first string was Hello World"
StringBuilder sbr = new StringBuilder("My Favourate Programming Font is ");
Console.WriteLine("sbr = {0}", sbr);
Console.WriteLine("Instance Id : {0}", idGenerator.GetId(sbr, out blStatus));
Console.WriteLine("this instance is new : {0}\n", blStatus);
sbr.Append("Inconsolata");
Console.WriteLine("sbr = {0}", sbr);
Console.WriteLine("Instance Id : {0}", idGenerator.GetId(sbr, out blStatus));
Console.WriteLine("this instance is new : {0}\n", blStatus);
//Now sbr="My Favourate Programming Font is Inconsolata"
Console.ReadKey();
}
}
输出将如下所示
当str与“Hello World”连接时,字符串的实例id从1更改为2。而sbr的实例id在追加操作后也保持与3相同。这说明了所有关于可变性和不变性的问题。blStatus变量指示实例是否为新实例
您可以在以下位置找到关于该主题的完整文章:我可以证明
字符串
不是不变的。我所需要做的就是显示一些变异字符串的代码,如下所示:
using System;
using System.Runtime.InteropServices;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
const string test = "ABCDEF"; // Strings are immutable, right?
char[] chars = new StringToChar {str = test}.chr;
chars[0] = 'X';
// On an x32 release or debug build or on an x64 debug build,
// the following prints "XBCDEF".
// On an x64 release build, it prints "ABXDEF".
// In both cases, we have changed the contents of 'test' without using
// any 'unsafe' code...
Console.WriteLine(test);
// The following line is even more disturbing, since the constant
// string "ABCDEF" has been mutated too (because the interned 'constant' string was mutated).
Console.WriteLine("ABCDEF");
}
}
[StructLayout(LayoutKind.Explicit)]
public struct StringToChar
{
[FieldOffset(0)] public string str;
[FieldOffset(0)] public char[] chr;
}
}
现在,这是否应该被视为C#中的错误是另一回事
(答案可能是FieldOffset
应该被认为是不安全的
——上面的代码据称是安全的
,因此字符串
不应该是可变异的。)
此外,我认为您可以合理地争辩说,string
在精神上是不可变的,即使在假定安全的代码中存在违反其不可变性的愚蠢边缘情况。检查两个string对象的对象引用,它们是一样的。写一个连接字符串的循环,然后看着GC发疯,你的应用程序像发疯一样耗尽内存?你不能——事实上你可以证明你可以使用不安全的代码来改变字符串。您所能做的最好的事情就是指向承诺字符串是不可变的规范(在CLR安全代码的上下文中)。如果你的工作是编程,你必须习惯于相信语言规范——如果语言没有按照规范所说的去做,那么编译器团队就要修复它。您可以演示一个示例,其中字符串没有变异,但它不能证明任何东西。可能存在这样失败的构造。在你找到一个之前,你必须相信规范。他们可能只是想听听你如何处理问题,你的想法,讨论等等。并不是真的希望你证明字符串是不可变的。否则,这就是一个不太好的面试问题:)@M.kazemAkhgary是的,但这可以在C#本身的范围内完成。这不像我们在使用调试器、反汇编程序、代码注入或其他任何东西——只是完全有效的C代码。如果面试官想要一个更具体的答案,他们应该问一个更连贯、更具体的问题。让我先检查一下,如果答案正确,我会接受你的回答。这只能证明你正在测试的运算符和方法创建了新的字符串实例。这并不能证明字符串总是不可变的。参见J在问题下方的评论,为什么不可能用数学/科学意义上的证明来证明。‒-1对于绝对错误的陈述,可以证明c#string的不变性,如果您编辑您的答案以删除此断言并合并@René提供的信息,将切换到upvoteVogt@samurai我认为你可能需要更仔细地考虑形势的逻辑。字符串不能同时是不可变和可变的。由于前者是否定的证明,后者立即使任何假定的否定证明无效。“如何证明c#字符串是不可变的”这个问题的答案是,你不能,因为它们不是不可变的。仅仅因为它们在某些情况下没有变异,并不能证明它们不能变异。@samurai Simple logic,如果您可以通过显示一个可以变异的情况来直接证明string
是可变的,这意味着它不能是不变的。@Sylverac还可以用我最新编辑的代码来尝试,我在其中添加了Console.WriteLine(“ABCDEF”));代码>-它甚至不再打印“ABCDEF”@Sylverac不,一点都不一样。当您连接新字符串时,编译器并不是直接自己创建新字符串,而是String
中连接方法的实现(请查看中的实现)。它们创建并返回对新字符串的引用。还要注意的是,str+=“XXX”
string串联转换为对str=string.Concat(str,“XXX”)
的调用。为+=
创建了新字符串,但我的代码没有创建它们。@Sylverac发生的事情是:首先创建StringToChar
结构的一个实例,并将对字符串test
的引用分配给结构的str
字段(注意:分配的是引用,而不是字符串的副本)。然后,结构中的chr
字段用于访问字符串的内容,就像它是一个字符数组一样(即提供对字符串内容的直接访问)。通过使用<代码>字段偏移(0)< /C> >使结构像C++联盟一样运行。最后,代码更改了char数组的第一个元素(它更改了底层字符串)。