字符串的构造函数
本文关键字:构造函数 字符串 | 更新日期: 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];
——不是创建一个新对象,而是简单地返回一个对象的引用,该对象是在加载类时创建的。