问题描述
In .NET, a value type (C# struct
) can't have a constructor with no parameters. According to this post this is mandated by the CLI specification. What happens is that for every value-type a default constructor is created (by the compiler?) which initialized all members to zero (or null
).
Why is it disallowed to define such a default constructor?
One trivial use is for rational numbers:
public struct Rational {
private long numerator;
private long denominator;
public Rational(long num, long denom)
{ /* Todo: Find GCD etc. */ }
public Rational(long num)
{
numerator = num;
denominator = 1;
}
public Rational() // This is not allowed
{
numerator = 0;
denominator = 1;
}
}
Using current version of C#, a default Rational is 0/0
which is not so cool.
PS: Will default parameters help solve this for C# 4.0 or will the CLR-defined default constructor be called?
Jon Skeet answered:
To use your example, what would you want to happen when someone did:
Rational[] fractions = new Rational[1000];
Should it run through your constructor 1000 times?
Sure it should, that's why I wrote the default constructor in the first place. The CLR should use the default zeroing constructor when no explicit default constructor is defined; that way you only pay for what you use. Then if I want a container of 1000 non-default Rational
s (and want to optimize away the 1000 constructions) I will use a List<Rational>
rather than an array.
This reason, in my mind, is not strong enough to prevent definition of a default constructor.
Note: the answer below was written a long time prior to C# 6, which is planning to introduce the ability to declare parameterless constructors in structs - but they still won't be called in all situations (e.g. for array creation) (in the end this feature was not added to C# 6).
EDIT: I've edited the answer below due to Grauenwolf's insight into the CLR.
The CLR allows value types to have parameterless constructors, but C# doesn't. I believe this is because it would introduce an expectation that the constructor would be called when it wouldn't. For instance, consider this:
MyStruct[] foo = new MyStruct[1000];
The CLR is able to do this very efficiently just by allocating the appropriate memory and zeroing it all out. If it had to run the MyStruct constructor 1000 times, that would be a lot less efficient. (In fact, it doesn't - if you do have a parameterless constructor, it doesn't get run when you create an array, or when you have an uninitialized instance variable.)
The basic rule in C# is "the default value for any type can't rely on any initialization". Now they could have allowed parameterless constructors to be defined, but then not required that constructor to be executed in all cases - but that would have led to more confusion. (Or at least, so I believe the argument goes.)
EDIT: To use your example, what would you want to happen when someone did:
Rational[] fractions = new Rational[1000];
Should it run through your constructor 1000 times?
- If not, we end up with 1000 invalid rationals
- If it does, then we've potentially wasted a load of work if we're about to fill in the array with real values.
EDIT: (Answering a bit more of the question) The parameterless constructor isn't created by the compiler. Value types don't have to have constructors as far as the CLR is concerned - although it turns out it can if you write it in IL. When you write "new Guid()
" in C# that emits different IL to what you get if you call a normal constructor. See this SO question for a bit more on that aspect.
I suspect that there aren't any value types in the framework with parameterless constructors. No doubt NDepend could tell me if I asked it nicely enough... The fact that C# prohibits it is a big enough hint for me to think it's probably a bad idea.
这篇关于为什么我不能在 .NET 中为结构定义默认构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!