字符串的构造函数

本文关键字:构造函数 字符串 | 更新日期: 2023-09-27 18:08:34

我们可以说

string myString = "Hello";

它"神奇地"构造了一个新的字符串对象来保存该值。

为什么不能使用类似的"无构造"方法从我们在代码中定义的类创建对象?VS对string s的"魔力"是什么?对于enum s呢?

字符串的构造函数

基本上,它是c#语言规范的一部分:有字符串字面量,数字字面量,字符字面量和布尔字面量的语法,但仅此而已。

编译器使用这些文字来生成IL,对于中的大多数,有一个合适的指令用于"特定类型的常量",因此它被直接表示。decimal是一个例外,它是而不是 CLR的基本类型,因此必须有额外的支持。(这就是为什么在应用属性时不能指定decimal参数的原因,例如。)

查看发生了什么最简单的方法是使用ildasm(或类似的工具)来查看为源代码的任何特定位生成的IL。

在创建自己的类方面,可以提供从string(或其他东西)到自己的类型的隐式转换,但这不会有完全相同的效果。您可以编写源代码:
MyType x = "hello";

…但这不会是MyType类型的"常量"……它只是一个使用隐式转换的初始化式

事实上,您可以为您的自定义类这样做。这是通过定义来自其他类型的隐式转换来实现的。在msdn: http://msdn.microsoft.com/en-us/library/aa288476%28v=vs.71%29.aspx

中有很好的介绍

下面是一个修改字符串的例子:

class Email
{
    private string user;
    private string domain;
    public Email(string user, string domain)
    {
        this.user = user;
        this.domain = domain;
    }
    static public implicit operator Email(string value) // magic goes here ;)
    {
        var parts = value.Split('@');
        if (parts.Length != 2)
            return null;
        return new Email(parts[0], parts[1]);
    }
    static public implicit operator string(Email value)
    {
        return "{ User = " + value.user + ", Domain = " + value.domain + " }";
    }
}
class Test
{
    static public void Main()
    {
        Email test = "alice@test.com"
        System.Console.WriteLine("Test: " + test);
    }
}

c#编译器将其转换为相应的CIL指令:ldstr。对于您自己的复杂类型没有等效的,因此编译器必须发出newobj CIL指令,该指令调用您的类型的构造函数。您建议的语法将对用户隐藏此构造函数调用。

尽管实际机制与我将在这里描述的略有不同,但重要的是要认识到,当代码string myString = "Hello"; 执行时,不会创建字符串。相反,字符串是在加载代码时创建的

每个程序集的代码都包含大量二进制数据,数据与代码一起被读入数组。如果代码包含23个不同的字符串字面值,那么所有这些字面值的内容将与23个条目一起出现在数组中,每个条目列出一个字符串的起始索引和长度。这个过程在概念上类似于:

char[] RawData;  // Gets loaded by the runtime
string [] StringLiterals;
void create_strings()
{
  int numStrings = (int)RawData[0] + 65536*(int)RawData[1];
  StringLiterals= new string[numStrings];
  for (int i=0; i<numStrings; i++)
  {
    int header = i*4+2;
    int startLoc = (int)RawData[header] + 65536*(int)RawData[header+1];
    int length  = (int)RawData[header+2] + 65536*(int)RawData[header+3];
    StringsLiterals[i] = new String(RawData, startOfs, length);
  }
}

如果"Hello"恰好是程序集中定义的第7个字符串,那么字符"Hello"将出现在RawData中条目#7定义的位置。上述语句将被翻译为string myString = StringLiterals[7];——不是创建一个新对象,而是简单地返回一个对象的引用,该对象是在加载类时创建的。