115

After failing to get something like the following to compile:

public class Gen<T> where T : System.Array
{
}

with the error

A constraint cannot be special class `System.Array'

I started wondering, what exactly is a "special class"?

People often seem to get the same kind of error when they specify System.Enum in a generic constraint. I got the same results with System.Object, System.Delegate, System.MulticastDelegate and System.ValueType too.

Are there more of them? I cannot find any info on "special classes" in C#.

Also, what is so special about those classes that we can't use them as a generic type constraint?

  • 14
    I don't think this is a direct duplicate. The question isn't "why can't I use this as a constraint", it is "what are these special classes". I've had a look at those questions and they just state why it would be useless to use as a constraint, not explaining what a "special class" actually is and why it is considered special. – Adam Houldsworth Apr 30 '15 at 07:45
  • 2
    In my experience, classes that are used but you can't use them directly, only implicitly through other syntax, is special classes. Enum falls into the same category. What exactly makes them special, I don't know. – Lasse V. Karlsen Apr 30 '15 at 07:45
  • @AndyKorneyev: that question is sort of different. I am asking for a definition of a "special class" and/or a comprehensive list of these. That question simply asks for the reason System.Array can't be a generic type constraint. –  Apr 30 '15 at 07:45
  • From the [documentation](https://msdn.microsoft.com/en-us/library/system.array%28v=vs.110%29.aspx) it states "[...]only the system and compilers can derive explicitly from the Array class.". It's likely this is what makes it a special class - it is treated specially by the compiler. – RB. Apr 30 '15 at 07:47
  • 1
    @RB.: wrong. This logic would mean `System.Object` is *not* a "special class", as this is valid: `public class X : System.Object { }`, but `System.Object` is still a "special class". –  Apr 30 '15 at 07:49
  • @Mints97 Fair point - perhaps there are multiple definitions for special :) – RB. Apr 30 '15 at 07:49
  • @Mints97, `System.Object` is a special special class, since all other types derive from it, whether they like it or not. – Arturo Torres Sánchez Apr 30 '15 at 21:41

7 Answers7

106

From the Roslyn source code, it looks like a list of hardcoded types in isValidConstraintType:

switch (type.SpecialType)
{
    case SpecialType.System_Object:
    case SpecialType.System_ValueType:
    case SpecialType.System_Enum:
    case SpecialType.System_Delegate:
    case SpecialType.System_MulticastDelegate:
    case SpecialType.System_Array:
        // "Constraint cannot be special class '{0}'"
        Error(diagnostics, ErrorCode.ERR_SpecialTypeAsBound, syntax, type);
        return false;
}
Kobi
  • 135,331
  • 41
  • 252
  • 292
  • 1
    @kobi 702 becomes compiler error CS0702, as seen in the compiler output (which this question neglected to quote) and other answers. – AakashM Apr 30 '15 at 08:38
  • 1
    @AakashM - Thanks! I tried to compile and didn't get the error number, for some reason. It then took me *almost* 5 minutes to find out, and didn't have enough time to edit my comment. Sad story. – Kobi Apr 30 '15 at 08:40
  • 1
    @Kobi: you have to look at the _output_-window, there you find the exact compiler error code number `CS0702`. – Tim Schmelter Apr 30 '15 at 09:13
  • 11
    So now the real question is _why_ are these special classes? – David says Reinstate Monica Apr 30 '15 at 16:53
  • @DavidGrinberg Maybe the reason is you cannot inherit from these types directly (except for `object`), or at least it has something to do with it. Also `where T : Array` would allow passing Assay as T, which is probably not what most people want. – IS4 Feb 23 '16 at 18:57
  • The answers should focus more on the question at hand. The question is "what are special classes". Special classes cannot be used for inheritance or constratint, but remain mysterious to me, and I would like to know more. Please avoid talking about constraints only. – alelom Jan 26 '23 at 19:41
42

I found a Jon Skeet comment from 2008 on a similar question: Why is the System.Enum constraint not supported.

I know this is a bit off topic, but he asked Eric Lippert (the C# team) about it and they provided this answer:

First off, your conjecture is correct; the restrictions on constraints are by and large artefacts of the language, not so much the CLR. (Were we to do these features there would be a few minor things we'd like to change in the CLR regarding how enumerable types are specified, but mostly this would be language work.)

Second, I would personally love to have delegate constraints, enum constraints, and the ability to specify constraints that are illegal today because the compiler is trying to save you from yourself. (That is, making sealed types legal as constraints, and so on.)

However, due to scheduling restrictions, we will likely not be able to get these features into the next version of the language.

Newteq Developer
  • 2,257
  • 1
  • 26
  • 32
Amir Popovich
  • 29,350
  • 9
  • 53
  • 99
  • 10
    @YuvalItzchakov - Is quoting Github\MSDN better? The C# team has gave a concrete answer regarding the issue or a similar one..It can't really hurt anyone. Jon Skeet just quoted them and is pretty reliable when it gets to C#.. – Amir Popovich Apr 30 '15 at 15:59
  • 5
    No need to get upset. I didn't mean this isn't a valid answer :) Was just sharing my thoughts on the foundation which is jonskeet ;p – Yuval Itzchakov Apr 30 '15 at 16:00
  • 41
    FYI BTW I think that's me you're quoting there. :-) – Eric Lippert Apr 30 '15 at 22:14
  • 2
    @EricLippert - That makes the quote even more reliable. – Amir Popovich May 01 '15 at 04:46
  • Domain of link in answer is dead. – Pang Jul 11 '17 at 07:31
  • The answers should focus more on the question at hand. The question is "what are special classes". Special classes cannot be used for inheritance or constratint, but remain mysterious to me, and I would like to know more. Please avoid talking about constraints only. – alelom Jan 26 '23 at 19:41
25

According to MSDN it's a static list of classes:

Compiler Error CS0702

Constraint cannot be special class 'identifier' The following types may not be used as constraints:

  • System.Object
  • System.Array
  • System.Delegate
  • System.Enum
  • System.ValueType.
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • 4
    Cool, seems like the right answer, good find! But where's `System.MulticastDelegate` in the list? –  Apr 30 '15 at 07:57
  • 8
    @Mints97: no idea, lack of documentation perhaps? – Tim Schmelter Apr 30 '15 at 08:09
  • 1
    Seems as though you also can't inherit from these classes. – David Klempfner Dec 06 '19 at 05:40
  • The answers should focus more on the question at hand. The question is "what are special classes". Special classes cannot be used for inheritance or constratint, but remain mysterious to me, and I would like to know more. Please avoid talking about constraints only. – alelom Jan 26 '23 at 19:40
14

As per C# 4.0 Language Specification (Coded : [10.1.5] Type parameter constraints) tells two things:

1] The type must not be object. Because all types derive from object, such a constraint would have no effect if it were permitted.

2] If T has no primary constraints or type parameter constraints, its effective base class is object.

When you define a generic class, you can apply restrictions to the kinds of types that client code can use for type arguments when it instantiates your class. If client code tries to instantiate your class by using a type that is not allowed by a constraint, the result is a compile-time error. These restrictions are called constraints. Constraints are specified by using the where contextual keyword. If you want to constrain a generic type to be a reference type, use : class.

public class Gen<T> where T : class
{
}

This will prohibit the generic type from being a value type, such as int or a struct etc.

Also, Constraint cannot be special class 'identifier' The following types may not be used as constraints:

  • System.Object
  • System.Array
  • System.Delegate
  • System.Enum
  • System.ValueType.
Community
  • 1
  • 1
Rahul Nikate
  • 6,192
  • 5
  • 42
  • 54
  • The answers should focus more on the question at hand. The question is "what are special classes". Special classes cannot be used for inheritance or constratint, but remain mysterious to me, and I would like to know more. Please avoid talking about constraints only. – alelom Jan 26 '23 at 19:40
12

There are certain classes in the Framework which effectively pass on special characteristics to all types derived from them but do not possess those characteristics themselves. The CLR itself imposes no prohibition against using those classes as constraints, but generic types constrained to them would not acquire the non-inherited characteristics the way concrete types would. The creators of C# decided that because such behavior might confuse some people, and they failed to see any usefulness to it, they should prohibit such constraints rather than allow them to behave as they do in the CLR.

If, for example, one were allowed to write: void CopyArray<T>(T dest, T source, int start, int count); one would be able to pass dest and source to methods which expect an argument of type System.Array; further, one would get compile-time validation that dest and source were the compatible array types, but one would not be able to access elements of the array using the [] operator.

The inability to use Array as a constraint is mostly pretty easy to work around, since void CopyArray<T>(T[] dest, T[] source, int start, int count) will work in almost all situation where the former method would work. It does, however, have a weakness: the former method would work in the scenario that one or both of the arguments was of type System.Array while rejecting cases where the arguments are incompatible array types; adding an overload where both arguments were of type System.Array would make the code accept the additional cases it should accept, but also make it erroneously accept cases it should not.

I find the decision to outlaw most of the special constraints irksome. The only one which would have zero semantic meaning would be System.Object [since if that were legal as a constraint, anything would satisfy it]. System.ValueType probably wouldn't be very useful, since references of type ValueType don't really have much in common with value types, but it might plausibly have some value in cases involving Reflection. Both System.Enum and System.Delegate would have some real uses, but since the creators of C# didn't think of them they're outlawed for no good reason.

supercat
  • 77,689
  • 9
  • 166
  • 211
10

The following can be found in CLR via C# 4th Edition:

Primary Constraints

A type parameter can specify zero primary constraints or one primary constraint. A primary constraint can be a reference type that identifies a class that is not sealed. You cannot specify one of the following special reference types: System.Object, System.Array, System.Delegate, System.MulticastDelegate, System.ValueType, System.Enum, or System.Void. When specifying a reference type constraint, you are promising the compiler that a specified type argument will either be of the same type or of a type derived from the constraint type.

Claudio P
  • 2,133
  • 3
  • 25
  • 45
  • See also: C#LS section 10.1.4.1: *The direct base class of a class type must not be any of the following types: `System.Array`, `System.Delegate`, `System.MulticastDelegate`, `System.Enum`, or `System.ValueType`. Furthermore, a generic class declaration cannot use `System.Attribute` as a direct or indirect base class.* – Jeroen Vannevel May 01 '15 at 00:11
  • The answers should focus more on the question at hand. The question is "what are special classes". Special classes cannot be used for inheritance or constratint, but remain mysterious to me, and I would like to know more. Please avoid talking about constraints only. – alelom Jan 26 '23 at 19:40
6

I don't think, that there exists any official definition of "special classes"/"special types".

You may think about them a a types, which can't be used with semantic of "regular" types:

  • you can't instantiate them directly;
  • you can't inherit custom type from them directly;
  • there is some compiler magic to work with them (optionally);
  • the direct usage of their instances at least useless (optionally; imagine, that you've created generic above, what generic code are you going to write?)

P.S. I'd add System.Void to the list.

Dennis
  • 37,026
  • 10
  • 82
  • 150
  • 2
    `System.Void` gives an entirely different error when used as a generic constraint =) –  Apr 30 '15 at 07:58
  • @Mints97: true. But if the question is about "special", then yes, `void` is very special. :) – Dennis Apr 30 '15 at 07:59
  • @Dennis: Code which has a couple parameters of a type constrained to `System.Array` could use methods like `Array.Copy` to move data from one to the other; code with parameters of a type constrained to `System.Delegate` would be able to use `Delegate.Combine` on them *and cast the result to the proper type*. Making effective use of a generic known type to be `Enum` will using Reflection once for each such type, but a generic `HasAnyFlag` method can be 10x faster than a non-generic method. – supercat May 01 '15 at 19:08