0

While learning about Generics I came to knew about Constraints on Type Parameters. One of these constraints is new() constraint. According to Microsoft:

The type argument must have a public parameterless constructor. When used together with other constraints, the new() constraint must be specified last.

Now I have a code like this.

using System;

namespace Test
{
    class A { }

    struct S { }

    enum E { }

    class Generics
    {
        public static void GenericMethod<T>() where T : new() 
        {
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Generics.GenericMethod<A>(); // Line 1
            Generics.GenericMethod<S>(); // Line 2
            Generics.GenericMethod<E>(); // Line 3
        }
    }
}
  • Line 1 does not generate error bcoz classes have default parameterless constructor.
  • Line 2 does not generate error bcoz structs have default parameterless constructor. And
  • Line 3 does not generate error but WHY?

Why does new() constraint allows enum to be passed as type argument?

Also I am able to do this

E e = new E();

in the above code.

Does this mean enums have parameterless constructor by default?

Edited: After reading answers and comments I thought enums contain default constructor. So I used reflection to see if I can print on the console the default constructor of enum E. The code is as follows

Type T = typeof(E);
Console.WriteLine("Constructors");
ConstructorInfo[] constructors = T.GetConstructors();
foreach (var constructor in constructors)
{
    Console.WriteLine(constructor.ToString());
}

But it doesn't prints anything.

So the question still remains Does an enum has a default parameterless constructor or not?

gamerdev
  • 65
  • 6
  • 4
    Haven't you answered your own question already? You've shown that enums do have a public parameter-less constructor. – Jonathon Reinhart Mar 03 '18 at 16:20
  • But I can't explicitly define another like in a class. – gamerdev Mar 03 '18 at 16:22
  • Enums are a class type, it's inheritance hierarchy is from System.Object and System.ValueType, it has a constructor, to read more about it: https://msdn.microsoft.com/en-us/library/system.enum(v=vs.110).aspx – Ryan Wilson Mar 03 '18 at 16:22
  • Here I am talking about the type enum not about class Enum they are both different. – gamerdev Mar 03 '18 at 16:24
  • @RyanWilson That is not what is usually called a class type. A class type is usually taken to mean a reference type which is not an interface (sometimes not a delegate type either). In any case, an enum is a value type. But it is true that it is inheriting, in a sense, the reference type `System.Enum` whose base class is `System.ValueType` (base `System.Object`). – Jeppe Stig Nielsen Mar 03 '18 at 16:37
  • Enums are mostly just ints, which also have a parameter-less default constructor (`new int()` is perfectly fine, but awkward) like any other object which doesn’t explicitly specifies a constructor. – ckuri Mar 04 '18 at 00:51
  • @ckuri are you saying that enums borrow parameterless constructor from their underllying type. – gamerdev Mar 04 '18 at 08:23
  • Then why didn't the reflection code printed any constructors on the console. – gamerdev Mar 04 '18 at 08:25
  • No, they don’t borrow - my comment was more about that enums for most of the parts just behave like their underlying type. The default constructor for value types is implicit. GetConstructors or any other reflection methods are likely to only return what is actually defined and won’t return syntactic sugar elements or language constructs. To go back to an int: technically it doesn’t need a constructor, because as a primitive there is nothing to construct - it’s just there, however language-wise every object has to have constructor. – ckuri Mar 04 '18 at 08:45
  • @JeppeStigNielsen While I agree that your definition of class type applies to most cases, MSDN still classifies ENUM as a base class "Enum is the base class for all enumerations in the .NET Framework." So, even though it is an abstract class, it still meets the criteria of not being an interface or delegate type. – Ryan Wilson Mar 04 '18 at 18:34
  • @RyanWilson Yes, the special abstract type `System.Enum` is a reference type which is not an interface and not a delegate type. However, you cannot use `System.Enum` as a type parameter `T` which has the constraint `where T : new()`. No abstract type can fulfil the `new()` constraint. It is different with an enum type (and `System.Enum` is ___not___ an enum type!). As an example, the type `Test.E` from the program above, that type is a value type. Any enum type such as `Test.E` (or, say, `System.DayOfWeek`) is allowed as the `T` constrained to `where T : new()`. – Jeppe Stig Nielsen Mar 05 '18 at 19:16
  • @JeppeStigNielsen I think we are agreeing on everything discussed, maybe my calling it a class type was not as descriptive as it should have been. – Ryan Wilson Mar 05 '18 at 19:41

2 Answers2

4

This is allowed because all specific enum types are value types. Hence, C# gives them a default constructor:

Each value type has an implicit default constructor that initializes the default value of that type.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • But why can't I explicitly define a constructor in an enum. – gamerdev Mar 03 '18 at 16:28
  • @Learner The only explicit members you can write in an `enum`, are the (automatically `public`) enumeration constants. – Jeppe Stig Nielsen Mar 03 '18 at 16:30
  • 1
    @Learner and what exactly are you going to do in that constructor if you were allowed to define it? – Evk Mar 03 '18 at 16:30
  • @Evk If it were allowed (it is not), you could have a non-static constructor that took in one or more arguments and contained logic to determine the value the enum. By unconditionally assigning to the field `this.value__` in the constructor body. – Jeppe Stig Nielsen Mar 03 '18 at 16:33
  • Just like @Jeppe said I could have some kind of logic to determine the value of enum. – gamerdev Mar 03 '18 at 16:40
0

Every value type T is allowed with the constraint where T : new(), including every enum type.

When new T() is used, it corresponds to the zero value of the value type. It is the same as default(T) for value types.

There is a more specific constraint, where T : struct, also allowing enum types (but not Nullable<>). This constraint "implies" the where T : new() in the sense that you cannot specify both because struct automatically contains new(). Again, in the case of a value type, new T() is the same as default(T).


EDIT: To address the new question:

Does an enum has a default parameterles constructor or not?

No, in reality a value type (including an enum) does not have this zero-parameter instance constructor. But the syntax new E() is still allowed, and produces the same "zero" value as does default(E). And it is specifically permitted to use a value type for a generic parameter T constrained to where T : new().

See related thread Why default constructor does not appear for value types?

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181