如何在C#中证明字符串的不变性?

时间:2016-05-16 11:52:26

标签: c# string immutability

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

3 个答案:

答案 0 :(得分:8)

我可以证明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不应该是可变的。)

另外,我认为你可以合理地争辩string在精神上是不可改变的,即使有些愚蠢的边缘案例在所谓的安全代码中违反了它的不变性。

答案 1 :(得分:1)

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

  

以下答案取自C#

String Vs Stringbuilder的dotmob文章

实际上ObjectIDGenerator将为我们在程序中创建的实例返回一个唯一的整数值。在这个类的帮助下,我们可以检查是否为string和stringbuilder上的各种操作创建了新实例.Consider跟随程序

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/

找到有关该主题的完整文章

答案 2 :(得分:-2)

一个简单的例子:

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

// output:test

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

// output:test

尝试此代码,如果字符串是可变的,“str2”应为“DDD”。