2016-05-16 35 views
7

在我上次的c#访问中,
我被要求证明C#字符串的不变性,我知道c#字符串的不变性是什么意思,但是有可能通过代码证明c#字符串的不变性吗?我可以有一个示例代码片段吗? 在此先感谢如何证明C#中字符串的不可变性?

+1

检查两个字符串对象的对象引用,它们将是相同的。 – Marshal

+2

编写一个连接字符串的循环,然后观察GC发疯,并且您的应用程序像疯了一样烧毁内存? – Nasreddine

+5

你不能 - 实际上,你确实可以证明你*可以*使用不安全的代码对一个字符串进行变异。你可以做的最好的事情是指向那些承诺字符串是不可变的规范(在CLR安全代码的上下文中)。如果你的工作是编程,你必须习惯于信任语言规范 - 如果语言不符合规范说明的话,这是编译器团队修复的一个错误。你可以演示一个字符串没有变异的例子,但它没有证明任何东西。有可能是构建失败的地方。直到你找到一个,你必须简单地相信规范。 –

回答

5

我能证明string一成不变的。所有我需要做的是显示一些代码,变异一个string,像这样:

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应该被认为是unsafe - 上面的代码是据称safe,因此string不应该mutatable)

另外,我觉得你可以合法地认为string是不可变的精神,即使在假定的安全代码中存在违反其不可变性的愚蠢的边缘案例。

+0

,将切换为upvote这是如何证明的字符串是可变的?这不是像'stringVariable + =“某些字符串”;'这样的概念吗?当你做了最后一行代码时,编译器不能简单地连接'stringVariable'的当前值和你提供的新字符串;相反,它会创建一个新的字符串对象,并将其设置为等于新的连接字符串。 –

+0

你证明字符串为可变对象,这是如何证明字符串的不变性,@ shamseer k smr回答正确答案 – samurai

+0

'FieldOffset'肯定应该是'unsafe',而不仅仅是因为这个例子。很好的例子。 –

1

是的,可以使用ObjectIDGenerator类证明c#字符串的不变性。

以下的答案必须从dotmob文章在C#中采取String Vs Stringbuilder

其实ObjectIDGenerator将返回情况下,我们在我们programs.With创建此类的帮助下,我们可以检查一个唯一的整数值是否创造了新的实例,或者不是为字符串和StringBuilder的各种操作。考虑下面的程序

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(); 
    } 
} 

输出将看起来像这样 enter image description here

当str与“Hello World”串联在一起时,字符串的实例ID从1变为2,同时追加操作后sbr的实例ID与3保持相同。这告诉所有关于易变性和不变性。 blStatus变量指示实例是否是新的。

你可以找到关于从主题完整的文章:http://dotnetmob.com/csharp-article/difference-string-stringbuilder-c/

+1

让我先检查它,如果它是正确的,我会接受你的回答 –

+2

这只能证明你正在测试的操作符和方法会创建新的字符串实例。它并不能证明字符串总是不变的。请参阅J下面的问题的评论,为什么不能用数学/科学的证明来证明这一点。 –

+2

感谢文章 – samurai

-2

一个简单的例子:

string str = "test";string str2 = str;Console.WriteLine(str2);

//输出:测试

str = "DDD";Console.WriteLine(str2);

//输出:测试

试试这个代码,如果字符串是可变的,“ str2“应该是”DDD“。