作为具有C,C++和汇编语言背景的人,一直困扰我的关于C#的一件事是我不能做这样的事情:
struct OperatorType
{
string Operator;
TokenType Type;
}
protected static OperatorType[] Operators = {
{ "{", TokenType.OpenBrace }
};
Run Code Online (Sandbox Code Playgroud)
我想声明这一点,以便在运行时不需要分配和初始化,但C#不允许它.
是的,我知道我可以初始化new OperatoryType() { Operator = "{", Type = TokenType.OpenBrace }.但这不涉及内存的运行时分配和初始化吗?我知道这不是那么多开销,但我不明白为什么这里有必要.
任何人都可以解释为什么C#需要这些额外的开销,或者可能没有运行时分配的方法吗?
无论是在C#还是C++中,分配总是需要在运行时进行分配.更重要的是分配何时发生.
如果在C#中使用静态构造函数进行分配,则会在第一次使用该类型之前的某个时间进行分配.这应该是安全的,与C++版本相比,并没有任何额外的开销.
此外,有一点需要注意 - C#中的运行时分配往往比C++便宜得多.这是垃圾收集器的一个巨大优势.这很可能是过早优化的经典案例.我建议不要担心这个问题,除非你发现了一个真实的,经过测量的性能问题.
简单地从二进制文件映射静态数据的问题是它需要在编译时冻结所有数据的格式.由于运行时确定了结构的布局(包括字符串和数组),因此编译器无法知道布局是什么.即使编译器发出了当前运行时的布局,也可能会被未来的运行时破坏.这意味着只有在该程序集中定义的具有显式布局的结构才能从文件静态映射,这很坦率地说并不太有用.
C#语言规范4.0,第7.6.10.4节说:
除了在不安全的上下文(第18.1节)中,数组的布局未指定.
在18.5.8:
未指定成员打包到结构中的顺序.
string在.NET 3.5和4.0之间实际改变了布局(他们删除了一个字段); 它来自
[NonSerialized]
private int m_arrayLength;
[NonSerialized]
private char m_firstChar;
[NonSerialized]
private int m_stringLength;
Run Code Online (Sandbox Code Playgroud)
至
[NonSerialized, ForceTokenStabilization]
private char m_firstChar;
[NonSerialized]
private int m_stringLength;
Run Code Online (Sandbox Code Playgroud)
这在C或C++中不是问题,因为编译器确定了结构的布局.当然,这也意味着您必须重新编译使用struct/class的所有内容才能更改其布局.