开发者

C# Array Initialization

As someone with a background in C, C++ and assembly language, one thing that has always bothered me about C# is that I cannot do something like this:

struct OperatorType
{
    string Operator;
    TokenType Type;
}

protected static OperatorType[] Operators = {
    { "{", TokenType.OpenBrace }
};

I'd like to declare this so that it doesn't require allocation and initialization at run time but C# won't allow开发者_JAVA技巧 it.

Yes, I understand I can initialize with new OperatoryType() { Operator = "{", Type = TokenType.OpenBrace }. But doesn't that involve a run-time allocation and initialization of memory? I know it's not that much overhead but I don't understand why it is necessary here.

Can anyone explain why this bit of additional overhead is required by C#, or possibly a way to do this without the run-time allocation?


Allocations, whether in C# or C++, always require allocation at runtime. It's more a matter of when the allocations occur.

If you allocate in a static constructor in C#, you'll allocate sometime before the first usage of the type. That should be safe, and not really have any extra overhead when compared to your C++ version.

Also, one thing to realize - runtime allocations in C# tend to be much cheaper than C++. This is one huge advantage of the garbage collector. It's very likely this is a classic case of premature optimization. I would recommend not worrying about this unless you've found a real, measured performance issue.


The problem with having static data simply mapped from a binary file is that it requires the format of all the data to be frozen at compile time. Since the runtime determines the layout of structures (including strings and arrays), the compiler can't know what the layout will be. Even if the compiler emitted the layout of the current runtime, it could be broken by future runtimes. This means that only structs with explicit layout that were defined in that assembly could be statically mapped from a file, which is quite frankly not too useful.

The C# Language Specification 4.0, section 7.6.10.4 says:

Except in an unsafe context (§18.1), the layout of arrays is unspecified.

In 18.5.8:

The order in which members are packed into a struct is unspecified.

The layout of string actually changed between .NET 3.5 and 4.0 (they removed a field); it went from

[NonSerialized]
private int m_arrayLength;
[NonSerialized]
private char m_firstChar;
[NonSerialized]
private int m_stringLength;

to

[NonSerialized, ForceTokenStabilization]
private char m_firstChar;
[NonSerialized]
private int m_stringLength;

This isn't a problem in C or C++ because the compiler determines the layout of structs. Of course this also means that you have to recompile everything that uses a struct/class in order to change its layout.


You could use a non default constructor to get a slightly more efficient version than using the object initializer syntax. There isn't really a runtime allocation other than the actual Operators array, the constructor will just get called for each location in that array

enum TokenType { OpenBrace, T2 };

struct OperatorType
{
    string Operator;
    TokenType Type;

    public OperatorType(string op, TokenType type)
    {
        Operator = op;
        Type = type;
    }
}

static OperatorType[] Operators = {
    new OperatorType( "{", TokenType.OpenBrace )
};


A simple answer to your question: by design. And I believe the syntax in your question is theoretically possible to implement. But as Eric Lippert often answers those questions like "why can't I ... in C#":

because no one ever designed, specified, implemented, tested, documented and shipped that feature. All six of those things are necessary to make a feature happen.


If you don't want it to initialize at runtime, then do the creation of it in the static constructor. So it won't get created until you call the class.Operators for the first time.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜