C# Generics: Constraining T where T : Object doesn't compile; Error: Constraint cannot be special class 'object'
Solution 1
There is no difference between the two constraints, except for that one is disallowed for being useless to explicitly state.
The C# 4.0 language specification (10.1.5 Type parameter constraints) says two things about this:
The type must not be object. Because all types derive from object, such a constraint would have no effect if it were permitted.
...
If T has no primary constraints or type parameter constraints, its effective base class is object.
In your comment, you said that you were trying to make T
be of type Void
. Void
is a special type that indicates that there is no return type and cannot be used in place of T
, which requires an appropriate concrete type. You will have to create a void version of your method and a T
version if you want both.
Solution 2
If you want to constrain a generic type to be a reference type, use : class
.
public interface IDoWork<T> where T : class
{
T DoWork();
}
This will forbid the generic type from being a value type, such as int
or a struct.
makerofthings7
Updated on September 30, 2020Comments
-
makerofthings7 over 3 years
When I constrain T with : Object like this:
public interface IDoWork<T> where T : Object { T DoWork(); }
I get the error:
Constraint cannot be special class 'object'
Does that mean there is an implied difference with the following that does compile?
public interface IDoWork<T> // where T : Object { T DoWork(); }
-
Thomas Levesque almost 12 yearsI don't know what the interface is used for, but it seems strange to forbid value types... a task that returns an int or a bool is fairly common.
-
Douglas almost 12 yearsYour point is valid, but I don’t know what the intention of the OP is either. I assumed that
: Object
meant that they were trying to constrain to reference types. -
supercat over 11 years@ThomasLevesque: There are many situations where generic code will work with any reference type, but cannot work with any generic value types; a simple example would be any code that either uses
Interlocked.CompareExchange
or other uses generic classes that do so. Astruct
constraint isn't quite so useful, though it does allow a type to be used as aNullable<T>
. Also, there are situations where value types which implements an interface "properly" may work, but classes that implement the interface cannot possibly work. -
C-F about 10 yearsBrilliant! Exactly what I was looking for :)
-
ToolmakerSteve over 8 yearsA common reason to restrict to reference type: Desire to return
null
when a valid object cannot be returned.null
is only meaningful/valid for reference types. -
ToolmakerSteve over 8 yearsThis answer would be useful if it explained why these are not meaningful as constraints, and what to do instead. I don't have an answer for such questions, but here is another link with more discussion of constraints: msdn.microsoft.com/en-us/library/d5x73970.aspx
-
Rahul Nikate over 8 years@ToolmakerSteve I've elaborated my answer a bit.
-
Nyerguds over 8 yearsWhat about structs, though? I tried this to disallow a ton of non-nullable things like 'int'.
-
George Birbilis over 6 yearsthanks for the tip, I was trying object instead of class myself too. My case was: interface IItemFactory<Item> where Item: class { Item Create(Item copyFrom = null); } - trying to use a default null value there and it was complaining without the constraint. Also tried Item? and Nullable<Item> in the method to no avail (was showing different errors). Guess those would work if I has a constraint to a struct or something. Wonder how you can make it to accept a null default parameter for any time (both value and reference types)
-
Douglas over 6 years@GeorgeBirbilis: Specifying a parameter type of
T?
would be allowed if you provide a generic constraint ofwhere T : struct
. This unfortunately means that you cannot directly share the implementation between classes and nullable structs, but you could do so indirectly (through private classes or methods). -
George Birbilis over 6 yearsthe question is though, if the compiler should be more clever there and allow Item Create(Item? copyFrom = null) for any type, both objects and non-object types, since I write Item? - it doesn't seem to allow that either though
-
Douglas over 6 years
T?
is just syntactic sugar forNullable<T>
, which is a struct that wraps other value types:public struct Nullable<T> where T : struct
. It cannot be used for reference types, which are intrinsically nullable in .NET. I agree; the language could have been designed to support common implementations for the two, but it doesn't.