After reading this question asking what exactly a “Special Class” is, I am left with the question why the six classes System.Object
, System.Array
, System.Delegate
, System.Enum
and System.ValueType
were chosen and hard-coded as special classes, preventing them from being used as constraints to generic classes or methods.
It is quite conceivable to understand why System.Object
is in there; all classes inherit System.Object
so there is no need to include it as a constraint. What I am unclear about is why the others were chosen to be part of this special classes category.
PS: The Special Classes raise the compile error CS0702 when an attempt is made to use them as constraints.
Those classes were already different before generic constraints, or even generics, were added to the .NET framework and support for them added to the C# language.
What each of them have in common, is that inheriting from them is different than with other types:
System.Object
: You can't not inherit from this in C#.
System.Array
: You inherit from this by creating an array of an existing type (Array x = new int[2];
etc.)
System.Delegate
: You inherit from this by creating a delegate
(which then derives from MulticastDelegate
, also a "special type", which derives from Delegate
).
System.Enum
: You inherit from this by creating an enum
.
System.ValueType
: You inherit from this by creating a struct
.
Now, note that aside from new()
generic constraints are all about inheritance or implementation of interfaces (which is akin to inheritance in many ways). Indeed the other restrictions are that you can't use a pointer type, and you can't use a sealed type; two cases where you can't have a derived type anyway (though the the ban on sealed types is primarily because you are likely creating a generic type or method when you don't need too, and is an attempt to protect you from yourself).
And as such code that is based on inheritance features (as constraints are) when faced with special cases about inheritance will likely have to itself involve special cases. Those special cases were dealt with in the simplest way: By prohibiting them.
The value is also less in many of these cases:
System.Object
: Since the only types that can't be converted to System.Object
are pointer types, and these can't be used as generic parameters anyway, any such constraint is redundant.
System.Array
: You can define in terms of element types: void DoSomethingWithArray<T>(T[] array)
etc.
System.Delegate
: Such would be useful, though in many cases we can define in terms of parameter and/or return types, but there are cases this doesn't catch.
System.Enum
: Would be useful.
System.ValueType
: Already dealt with; constrain as struct
. Conversely we can also constrain as class
to exclude this case so we've actually a "not inherited from…" option we don't have otherwise.
This is not to deny that being able to constrain in terms of Delegate
, MulticastDelegate
or Enum
would not be useful (probably most so we Enum
), but in terms of justifying the extra work to cover these types the others would give little or no benefit, so the benefit of less restrictions is reduced.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With