33

I've been trying this, but I can't seem to figure this out. I want to do this...

public abstract class SingletonType<TSingleton, TBaseClass> : TBaseClass
    where TSingleton : TBaseClass, new()
    where TBaseClass : class
{
    static TSingleton _singleton;
    public static TSingleton Singleton
        => _singleton ?? (_singleton = new TSingleton());
}

The plan was to use it like this which would sort of 'wrap' the singleton pattern around a base class...

public class SingletonFoo : SingletonType<SingletonFoo, Foo> {
}

However, I keep getting this

Cannot derive from 'TBaseClass' because it is a type parameter

Um... I thought types were exactly what you do derive from!

So what am I missing?

Note: This is, of course, a trivial example as it doesn't add anything helpful, but assume SingletonType has a lot of other logic which isn't relative to the question, hence it was omitted to focus on the question at hand.

7
  • 1
    You say, “Um... I thought types were exactly what you do derive from!” — Yes, but read the message again. It says “type parameter”, not “type”. That’s a difference. Commented May 4, 2011 at 22:22
  • Yet you can use that 'Type parameter' everywhere in the generic that you use a type (e.g. 'public static T') so how is using it the way I want different from using it as a return type? (So far @Tejs seems to have the most insight.) Commented May 4, 2011 at 22:24
  • It might be worth noting that composition would be ideal here as opposed to inheritance. Commented May 4, 2011 at 22:24
  • @Mohamed Nuur, Care to elaborate? (...or can anyone?) Not sure what you mean. Commented May 4, 2011 at 22:33
  • 1
    Possible duplicate of Why cannot C# generics derive from one of the generic type parameters like they can in C++ templates? Commented Jan 9, 2018 at 12:38

4 Answers 4

33

Generic types in C# are not C++ templates; remember, a generic type must work for all possible type arguments. A template need only work for the constructions you actually make.

This question is a duplicate; see my answer to

Why cannot C# generics derive from one of the generic type parameters like they can in C++ templates?

for more thoughts on this. Basically, the short answer is that the considerable costs do not outweigh the small benefits of the feature. If you don't like that answer, see my second answer:

Why cannot C# generics derive from one of the generic type parameters like they can in C++ templates?

And if you don't like that answer either, see the follow-up question:

What are the good reasons to wish that .NET generics could inherit one of the generic parameter types?

Sign up to request clarification or add additional context in comments.

Comments

19

No, this is not possible. For example, take a type that is declared sealed. You can't inherit from that class, and there is no constraint to limit to non sealed types, ergo trying to inherit from it via a generic parameter is impossible.

12 Comments

Well, this doesn’t really explain why — the compiler could just disallow the use of MyType<X> where X is the sealed type, instead of disallowing the declaration MyType<T> : T entirely. But of course the answer is still “it’s not possible” :)
Well, the why is that the generic parameter must be valid for all types allowed; for example, the new() constraint allows you to write T sample = new T(), because otherwise your generic parameter could be int and that is not valid code. Without a nosealed constraint, it would be a violation of the C# spec to inherit something with sealed. Because not all cases are valid for a type, and no constraint exists, it is not valid. The error message IS the compiler disallowing this from happening =D
No, the superficial why is that the spec says that the base type cannot be a type parameter, full stop. The deep why that you’re trying to provide is why the spec was written that way. You’re providing a non-explanation for that.
(By the way, as a nitpick, int does have a default constructor and therefore satisfies the new() constraint, as do all value types.)
@MarqueIV: Your comment makes no sense. There is no object constraint. Maybe you mean class, but then your comment is wrong: you can have a new() constraint without a class constraint.
|
0

Every type has exactly 1 real, discrete parent class, even when generics are involved. Even when dealing with an open generic type (e.g., typeof(List<>)), you can still find the parent class.

If what you wanted were allowed, this would not be true, typeof(SingletonType<,> would not have a parent type, and this is not allowed.

Comments

-2

No, it's not possible, because let's say you have this class:

class bar {
  int example = 0;
}

Now here's our type parameter class:

class foo<T> : T {
  int example = 5;
}

If we created a variable of type foo<bar> then example would get mixed up.

5 Comments

How would it get mixed up? ‘Bar’ there is a type parameter, not a base class. They are completely unrelated and in different scopes.
@MarqueIV No, because T is a type of bar of foo<bar>. Since the foo class inherits from the T class (bar) then example could be 0 or 5.
I’m sorry, but that’s incorrect. They are scoped completely different. You would access one example from the instance of your generic while you would access the other example from whatever instance variable inside your generic that’s defined via T. They are not the same thing.
You don't seem to understand how inheritance works in C#. example is private in bar so a derived class from bar can declare its own example without issue. Even if example were not private, then foo<T>'s example would be treated as new.
Ohh I see now, sorry for bothering

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.