C# Generics: Constraining T where T : Object doesn't compile; Error: Constraint cannot be special class 'object'

26,903

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.

Share:
26,903
makerofthings7
Author by

makerofthings7

Updated on September 30, 2020

Comments

  • makerofthings7
    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
    Thomas Levesque almost 12 years
    I 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
    Douglas almost 12 years
    Your 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
    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. A struct constraint isn't quite so useful, though it does allow a type to be used as a Nullable<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
    C-F about 10 years
    Brilliant! Exactly what I was looking for :)
  • ToolmakerSteve
    ToolmakerSteve over 8 years
    A 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
    ToolmakerSteve over 8 years
    This 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
    Rahul Nikate over 8 years
    @ToolmakerSteve I've elaborated my answer a bit.
  • Nyerguds
    Nyerguds over 8 years
    What about structs, though? I tried this to disallow a ton of non-nullable things like 'int'.
  • George Birbilis
    George Birbilis over 6 years
    thanks 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
    Douglas over 6 years
    @GeorgeBirbilis: Specifying a parameter type of T? would be allowed if you provide a generic constraint of where 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
    George Birbilis over 6 years
    the 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
    Douglas over 6 years
    T? is just syntactic sugar for Nullable<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.