Why exactly are these "Special Classes"?
Asked Answered
V

1

15

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.

Valuator answered 6/5, 2015 at 9:7 Comment(3)
All of the others are the roots of non-typical inheritance trees which have special language support to make use of.Cephalic
@Damien_The_Unbeliever: Fair enough. I would like to point out that there are typical cases where some of these constraints may be useful. Take for instance, a method that requires arguments to be of type Enum. By this restriction, writing a generic method with an Enum constraint is impossible unless one wants to use workarounds like Jon Skeet used in Unconstrained Melody. Admittedly, not everyone has the skill to do these workarounds even when they have legitimate reasons for wanting to use any of these "Special Classes" as constraints.Valuator
I think that they didn't foresee much use for these types in generics (although I agree I've wanted to do them with enums more than once) and I think that in the alternative, you'd have to implement lots of extra rules if you did allow them - i.e. you still have to treat them specially because e.g. ValueType is a reference type but all of the actual instances that derive from it are value types.Cephalic
C
7

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.

Cobos answered 12/5, 2015 at 12:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.