可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have written below code and it's compiling successfully.
class Program { enum Fruits { Apple, Mango, Banana } static void Main(string[] args) { Fruits f = new Fruits(); } }
Despite of Fruits being an enum, compiler and interpreter are allowing me to write this. Does this mean I can create a constructor for an enum? if yes then how?
回答1:
No, you can't.
new Fruits() will return the default value (the value corresponding to 0 in the underlying type of the enum), it's the same as default(Fruits) (or Fruits.Apple in your case).
Remeber that enums are only wrappers around a primitive type (int by default). You can pretty much compare new Fruits() to new int().
Usually you don't use the new Fruits()/new int() syntax as it's more common to just write 0 or default(T), but you may want to use it in generic code. As an example:
public T NewInstance<T>() where T : new() { return new T(); }
You are allowed to call NewInstance<Fruits>(), which will return Fruits.Apple.
回答2:
C# Spec:
An enum type is a distinct value type with a set of named constants.
As for the default value (as explained in the other answer):
The default value of any enum type is the integral value zero converted to the enum type. In cases where variables are automatically initialized to a default value, this is the value given to variables of enum types. In order for the default value of an enum type to be easily available, the literal 0 implicitly converts to any enum type.
Move the default constant to be the first in your enum.
回答3:
No. Check out the IL output (generated in LINQPad). It's not actually calling a constructor at all. Instead, it's storing the integer value 0 inside a local variable called f. This is the exact same output as you get when you use a type cast to the enum.
As far as the compiler is concerned, Fruits f = new Fruits(); is the same as Fruit f = (Fruit)0;.
Fruits f = new Fruits() IL
Program.Main: IL_0000: nop IL_0001: ldc.i4.0 IL_0002: stloc.0 // f IL_0003: ret Program..ctor: IL_0000: ldarg.0 IL_0001: call System.Object..ctor IL_0006: ret
For comparison, here's the IL output of a normal class. Look at IL_001 under Program.Main where it actually calls a constructor for the class.
Program.Main: IL_0000: nop IL_0001: newobj UserQuery+Program+Fruits..ctor IL_0006: stloc.0 // f IL_0007: ret Program..ctor: IL_0000: ldarg.0 IL_0001: call System.Object..ctor IL_0006: ret Fruits..ctor: IL_0000: ldarg.0 IL_0001: call System.Object..ctor IL_0006: ret
回答4:
For any value type, there is a parameterless constructor that returns the all-zero value. Hence:
var val = new int(); // 0 var val = new double(); // 0.0 var val = new DateTime(); // 0001-01-01T00:00:00.000000 Unspecified timezone var val = new StringSplitOptions(); // StringSplitOptions.None
However:
- You cannot add a new constructor for a type that isn't a
struct or a class, and so as far as value-types go, only struct. - You cannot change the implementation of any of these default constructors.
In the case of enums and primitives the constructor isn't even declared.
Hence you can't create such a constructor.
(Strictly speaking, .NET does allow you to set a defined parameterless constructor on a struct but C# doesn't, and if you do it in raw CIL there are inconsistent rules as to when it will be called and when you'll just get an all-zero instance created).