by skeet via Jon Skeet: Coding Blog on 12/10/2008 5:55:40 PM
There have been a couple of questions on StackOverflow about value types and parameterless constructors:
I learned quite a bit when answering both of these. When a further question about the default value of a type (particularly with respect to generics) came up, I thought it would be worth delving into a bit more depth. Very little of this is actually relevant most of the time, but it's interesting nonetheless.
I won't go over most of the details I discovered in my answer to the first question, but if you're interested in the IL generated by the statement "x = new Guid();" then have a look there for more details.
Let's start off with the first and most important thing I've learned about value types recently:
I very carefully wrote "in .NET" there - "in C#" would have been incorrect. I had always believed that the CLI spec prohibited value types from having parameterless constructors. (The C# spec used the terminology in a slightly different way - it treats all value types as having a parameterless constructor. This makes the language more consistent for the most part, but it does give rise to some interesting behaviour which we'll see later on.)
It turns out that if you write your value type in IL, you can provide your own parameterless constructor with custom code without ilasm complaining at all. It's possible that other languages targeting the CLI allow you to do this as well, but as I don't know any, I'll stick to IL. Unfortunately I don't know IL terribly well, so I thought I'd just start off with some C# and go from there:
I compiled that into its own class library, and then disassembled it with ildasm /out:Oddity.il Oddity.dll. After changing the constructor to be parameterless, removing a few comments, and removing some compiler-generated assembly attributes) I ended up with this IL:
ildasm /out:Oddity.il Oddity.dll
.assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) .ver 2:0:0:0 } .assembly Oddity { .hash algorithm 0x00008004 .ver 0:0:0:0 } .module Oddity.dll .imagebase 0x00400000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 .corflags 0x00000001 .class public sequential ansi sealed beforefieldinit Oddity extends [mscorlib]System.ValueType { .pack 0 .size 1 .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { .maxstack 8 IL_0000: nop IL_0001: ldstr "Oddity constructor called" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: ret } }
I reassembled this with ilasm /dll /out:Oddity.dll Oddity.il. So far, so good. We have a value type with a custom constructor in a class library. It doesn't do anything particularly clever - it just logs that it's been called. That's enough for our test program.
ilasm /dll /out:Oddity.dll Oddity.il
There are various things one could investigate about parameterless constructors, but I'm mostly interested in when they get called. The test application is reasonably simple, but contains lots of cases - each writes to the console what it's about to do, then does something which might call the constructor. Without further ado:
And here are the results:
So, to split these out:
Activator.CreateInstance<T>()
Activator.CreateInstance(Type)
default(T) in a generic method - this one didn't surprise me
new T()
Activator.CreateInstance<Oddity>()
Well, I'm still glad that C# doesn't let us define our own parameterless constructors for value types, given the behaviour. The main reason for using it - as far as I've seen - it to make sure that the "default value" for a type is sensible. Given that it's possible to get a usable value of the type without the constructor being called, this wouldn't work anyway. Writing such a constructor would be like making a value type mutable - almost always a bad idea.
However, it's nice to know it's possible, just on the grounds that learning new things is always a good thing. And at least next time someone asks a similar question, I'll have somewhere to point them...
Original Post: Value types and parameterless constructors
The content of the postings is owned by the respective author. CSharpFeeds is not responsible for the contents of the postings. This site is automatically generated and cannot be reviewed for abusive content. If you find abusive content on CSharpFeeds, please contact us. Designated trademarks and brands are the property of their respective owners. All rights reserved.