class constructors in a struct

  • Thread starter Thread starter Pent
  • Start date Start date
P

Pent

Hi All,

Why is this code valid? How can the static ctor be used? It doesn't act as
class ctor at all.

struct A
{
static A() { }
}
 
Hi Pent,
Pent said:
Why is this code valid?

Yes, it is valid.
How can the static ctor be used?

Static constructors is normally used to initialize static fields for a type.
It is quaranteed to be called before any static filed is accessed. Don't
realy on that the static constructor will be executed when the program
starts, type is instantiaded or a static method is called. The only sure
thing, how I said, is that the static constructor will be executed before a
static filed is accessed.
It doesn't act as class ctor at all.

Depends on what you mean by *class constructor*. CLR and IL Assembler call
*.cctor* (class constructor) the same thing that C# calls *static
constructor*. In this case it works how I already explained.
If for you *class ctor* means instance constructor defined for a class
(reference type) rather than for a struct (value type) then no, it doesn't.
struct A
{
static A() { }
}
If your problem is that you cannot declare parameterless constructor for
structures that's right - you cannot. This is because if you instatiate
value type without using *new* operator CLR doesn't call any constructor and
this may leave your object uninitialized. So C# designers decided not to
allow parameterless constructors for value types. This is good decision as
long as CLR works this way.

HTH
B\rgds
100
 
The question is: What's the purpose of the following code:

struct A
{
static A() { } //this is not called by CLR.
}

If there is no purpose for the above code, then why is it valid?
 
Pent,

Do you want the compiler to generate an error for each method with empty
body you may have?
Yes, your static constructor is redundant in this case, but it is not an
error neither can lead to errors (as parameterless-instance constructors for
value types). So why should be reported as so.

BTW excution can be slightly different if you have

struct Foo
{
static Bar bar = new Bar();
....... More static methods and fields
}

and

struct Foo
{
static Bar bar = new Bar();
...... More static methods and fields
static Foo(){}
}

Existence of redundant looking construtor in the second declaration may have
impact on the moment when bar field will be created (Bar's constructor will
be called).

B\rgds
100
 
100 said:
Static constructors is normally used to initialize static fields for a type.
It is quaranteed to be called before any static filed is accessed. Don't
realy on that the static constructor will be executed when the program
starts, type is instantiaded or a static method is called. The only sure
thing, how I said, is that the static constructor will be executed before a
static filed is accessed.

That's only true for types with the .beforefieldinit flag. For other
types, there are more rigid rules.
Depends on what you mean by *class constructor*. CLR and IL Assembler call
*.cctor* (class constructor) the same thing that C# calls *static
constructor*.

Not quite. It's more usually known as a "type initializer" in the ECMA
spec, although "class constructor" comes up as well - I'm not sure why
they have both versions.

In C#, you end up with a type initializer whenever you have static
fields which have initial values. Unless you have a static constructor
as well, the type is flagged as .beforefieldinit, which means that you
only get the guarantee that the type initializer will be called some
time before the fields get used for the first time. If you have a
static constructor as well, you get more rigidly defined behaviour -
the type initializer is only called when it absolutely has to be, but
before the first call to a static method, access of a static field, or
object construction.

See http://www.pobox.com/~skeet/csharp/beforefieldinit.html for more
explanation.
 
Hi Jon,
That's only true for types with the .beforefieldinit flag. For other
types, there are more rigid rules.

Yes, I know that. We had this discussion before, but as long as the question
wasn't "when the static constructor is called" I decided not to go into
details. I said "the only sure thing... " because this is the point where we
can say for sure that the static constructor has been called regardles of
whether ".beforefieldinit" has been set or not.
Not quite. It's more usually known as a "type initializer" in the ECMA
spec, although "class constructor" comes up as well - I'm not sure why
they have both versions.

*.cctor* stands for *class constructor* and I was guessing that this might
be the source of confusion.
Even though ECMA refers to that special method as *type initializer* CLR and
ILAsm uses *.cctor* as a name. Furthermore (how you mentioned) ECMA uses
*class constructor* as well; so, I don't thing that the actual name of this
special method is so important as long as it doesn't lead to
misunderstandings.

In C#, you end up with a type initializer whenever you have static
fields which have initial values. Unless you have a static constructor
as well, the type is flagged as .beforefieldinit, which means that you
only get the guarantee that the type initializer will be called some
time before the fields get used for the first time. If you have a
static constructor as well, you get more rigidly defined behaviour -
the type initializer is only called when it absolutely has to be, but
before the first call to a static method, access of a static field, or
object construction.

Actually, if *beforefieldinit* is not specified, calling the type
initializer is triggered by the first call to any static, instance or
virtual method or access any static or instance field. Which means when one
starts using the type.

However C# specs doesn't mention beforefieldinit anywhere; I was palying
arround and I couldn't get c# setting beforefieldinit for the type
initilizer of my test class. Either ILDasm doesn't show that flag or my c#
compiler doesn't use it. The tests, I performed, make me think that my c#
comppiler never sets the flag.
B\rgds
100
 
100 said:
Actually, if *beforefieldinit* is not specified, calling the type
initializer is triggered by the first call to any static, instance or
virtual method or access any static or instance field. Which means when one
starts using the type.

The only way to call a virtual method or use an instance field is to
create an instance though, surely... once an object which is an
instance of a type (even if the type is a base class of the most
specific type of the instance, as it were). (Apologies if this doesn't
make sense - I've only had 45 minutes of sleep in the last 30-odd
hours.)
However C# specs doesn't mention beforefieldinit anywhere; I was palying
arround and I couldn't get c# setting beforefieldinit for the type
initilizer of my test class. Either ILDasm doesn't show that flag or my c#
compiler doesn't use it. The tests, I performed, make me think that my c#
comppiler never sets the flag.

No - it *always* sets the flag if you don't include a static
constructor (at least in VS.NET 2003).

Try this:

using System;

class WithoutStaticConstructor
{
}

class WithStaticConstructor
{
static WithStaticConstructor()
{
}
}

Compile with:

csc /target:library Filename.cs

Open the dll and just expand the two types - beside the red triangle
WithStaticConstructor will have
..class private auto ansi
and WithoutStaticConstructor will have
..class private auto ansi beforefieldinit

(It works with exes as well.)
 
Jon Skeet said:
The only way to call a virtual method or use an instance field is to
create an instance though, surely... once an object which is an
instance of a type (even if the type is a base class of the most
specific type of the instance, as it were). (Apologies if this doesn't
make sense - I've only had 45 minutes of sleep in the last 30-odd
hours.)
Yep, What I said is what can be found in ECMA.
"4. If not marked BeforeFieldInit then that type's initializer method is
executed at (i.e., is triggered by):
* first access to any static or instance field of that type, or
* first invocation of any static, instance or virtual method of that type"

Of course you are right for that an instace or virtual method can be called
only if the object is created. When an isntance of a class is created the
instance constructor is executed and it triggers the class static
constructor, I believe. Structures, though, can be created without instance
constructor to be executed. In this case static constructor is not called
upon creation. But it will be called if an instace method is called.
No - it *always* sets the flag if you don't include a static
constructor (at least in VS.NET 2003).

Yes, you are right. I was so surprised of this my "discovery" so I was
inspecting my test project in the release subfolder until I was compiling in
debug version. ;)
However, the compiler doesn't put the beforefileinit flag C# specs will
still be satisfied.

"If a static constructor (§17.11) exists in the class,
execution of the static field initializers occurs immediately prior to
executing that static constructor. Otherwise,
the static field initializers are executed at an implementation-dependent
time prior to the first use of a static field
of that class."

Without .beforefieldinit everything is ok as well.

B\rgds
100
 
100 said:
Yep, What I said is what can be found in ECMA.
"4. If not marked BeforeFieldInit then that type's initializer method is
executed at (i.e., is triggered by):
* first access to any static or instance field of that type, or
* first invocation of any static, instance or virtual method of that type"

Of course you are right for that an instace or virtual method can be called
only if the object is created. When an isntance of a class is created the
instance constructor is executed and it triggers the class static
constructor, I believe. Structures, though, can be created without instance
constructor to be executed. In this case static constructor is not called
upon creation. But it will be called if an instace method is called.

Ah yes - good point.
Yes, you are right. I was so surprised of this my "discovery" so I was
inspecting my test project in the release subfolder until I was compiling in
debug version. ;)
:)

However, the compiler doesn't put the beforefileinit flag C# specs will
still be satisfied.

Yup - but as it does, people get confused :( That included me when
someone was saying a singleton was being created before he expected it
to be. I only found out about beforefieldinit at that stage...
 
Back
Top