I am a C++ programmer learning C#. I am currently reading C#4.0 in a Nutshell.
I have come accross this statement/snipet on page 74:
Static field initializers run in the order in which the fields are declared. The following example illustrates this: X is initialized to 0 and Y is initialized to 3.
class Foo
{
public static int X = Y; // 0
public static int Y = 3; // 3
}
I dont understand how X can be assigned the value in Y, without 开发者_如何学运维Y being first declared. Am I missing something here?
As an aside, coming from a C++ background, I tend to use the term ctor for constructor - however, I haven't yet come accross the term in C# - is the term ctor also used in the C# world?
[Edit]
A further example on the same page (in the book mentioned earlier) is this:
class Program
{
static void Main() { Console.WriteLine (Foo.X); } // 3
}
class Foo
{
public static Foo Instance = new Foo();
public static int X = 3;
Foo() { Console.WriteLine (X); } // 0
}
The book states (for the example above):
The example prints 0 followed by 3 because the field initializer that instantiates a Foo executes before X is initialized to 3:
I have some further questions w.r.t the examples.
Both examples appear under the section entitled Static constructors and field initialization order however, the code examples dont show a static ctor - atleast, not one that I can easily recognise. I was expecting a static ctor to have the same name as the class, be parameterless and be preceeded by the 'static' keyword. So I dont see how the examples relate to the section heading. What am I missing here?
In the second example, the (non static) ctor prints out the value of X - which had explicitly been assigned the value of 3 in the previous line - and yet, the output printed out is 0. Why?!
Order of declaration isn't important in terms of what's available here. It's not like the case where these are local variables, and a variable is only available after it's declared. The same is true for instance variables - and indeed methods, where a method declared earlier in the source can call one declared later in the source, etc.
However, the order of declaration is important in terms of execution of initializers, which is why you're getting that behaviour. Note that if you change these variables to const
, both will take the value 3 - the compiler will work out the required order of evaluation, and will detect if there are any cycles (Which would cause an error). The constants would then be evaluated at compile-time, and the values embedded directly in IL.
For more details about what's valid etc, consult the specification.
As for terminology - I don't usually see the need to abbreviate "constructor" to "ctor", although I think it would be generally understood. I might use that abbreviation for a variable name, for example:
var ctor = typeof(...).GetConstructor(...);
In C#, primitive types such as int
take on a default value. For int
, the default value is 0. This is not like C++ where you have to initialize the value or it will be getting a random dirty value from memory. Since Y is known to be of type int
, X can be assigned it's default value of 0.
As far as the keyword ctor
, I don't see it used very much as a C# programmer, but I am familiar with the term. I believe it is used in a few places in Visual Studio, for instance in the object browser.
Field declaration doesn't need to be in the order of dependency.
That is, you can use Y
above where you declare Y
.
The initialization, however, goes like this:
X
is initialized first, grabs its value fromY
, which is uninitialized, and thus0
(the default value for anint
)Y
is initialized to3
.
Initialisers are actually run in the constructor of the class. When the class is created, all static members are set to zero, then the static constructor runs. That is why the initialiser code can use the Y
field to initialise the X
field.
Your code works basically the same as:
class Foo {
public static int X; // 0
public static int Y; // 0
static Foo() {
X = Y; // 0
Y = 3; // 3
}
}
(There are however some differences between a class that has an explicit static constructor and one that doesn't, see Jon Skeet's article if you want to dig deeper.)
The term "ctor" is not widely used for "constructor" in C#, usually abbreviations like that are avoided in .NET. That is why identifiers tend to be lengthy and descriptive rather than short and cryptic, like StringComparison.CurrentCultureIgnoreCase
rather than something like str_cmp.cc_is
.
The abbreviation "ctor" is used in the templates in Visual Studio, by typing "ctor" and pressing tab, you get a template for a constructor.
if you create a class such as :
class Foo
{
public static int y1 = 3;
public static int x1 = y1;
public static int X = Y; // 0
public static int Y = 3; // 3
}
and disassemble it you will see
public static int y1 = 3;
00000021 mov dword ptr ds:[009E9360h],3
public static int x1 = y1;
0000002b mov eax,dword ptr ds:[009E9360h]
00000030 mov dword ptr ds:[009E9364h],eax
public static int X = Y; // 0
00000035 mov eax,dword ptr ds:[009E936Ch]
0000003a mov dword ptr ds:[009E9368h],eax
public static int Y = 3; // 3
0000003f mov dword ptr ds:[009E936Ch],3
Y has not been initialized and its default value is 0.
At first it seems a little weird, but in order to understand it, just remember they are fields, not local variables. Look at this:
class MyClass
{
public void MyMethod()
{
var a = field1;
}
int field1;
}
you can use the field1 in MyMethod, as you know the order of declaration is not important (in this matter) for class members.
The case above is just like this.
精彩评论