1

Disclaimer: Theoretical Question

The new constraint specifies that any type argument in a generic class declaration must have a public parameterless constructor.

Source: http://msdn.microsoft.com/en-us/library/sd2w2ew5(v=vs.80).aspx

What if I wanted my generic class to have a protected parameterless constructor instead? For instance, if I want to write a Singleton class which I "attach" to other classes to make them Singletons, I don't want the derived classes to be instantiable - everything should go through the .Instance property.

internal class Singleton<T> where T : new()
{
    public static T Instance { get; private set; }

    static Singleton()
    {
        Singleton<T>.Instance = new T();
    }
}

internal class OnlyOneOfMe : Singleton<OnlyOneOfMe>
{
    protected OnlyOneOfMe()
    {
    }
}

This way, Singleton<T> is able to create the only instance of the OnlyOneOfMe class, but nothing else can (unless it is a subclass).

"What if a generic parent class could access the generic type's protected members?"

Josh M.
  • 26,437
  • 24
  • 119
  • 200
  • 7
    If the constructor is protected, how do you intend to call it? – Lasse V. Karlsen May 12 '11 at 20:37
  • I know it's not supported but my thought process was: "if the derived class has a protected constructor, then the generic class (parent class) can see it, so it doesn't need to be public, right?" – Josh M. May 12 '11 at 20:44
  • 1
    No, wrong. Protected only works in one direction. Only descendants can access protected constructors, base types don't know about them at all. – Lasse V. Karlsen May 12 '11 at 20:45
  • Yes, I realize this! This is a theoretical question. – Josh M. May 12 '11 at 21:12
  • 1
    It is theoretical *now*, it wasn't previously. In any way, theoretical questions with no practical applicability is rather pointless. What if you could write English and the compiler understood that? That would be much better. – Lasse V. Karlsen May 12 '11 at 21:20
  • Since you have made this theoretical, you're in fact asking for opinions and musings, therefore I vote to close this question as subjective and argumentative. – Lasse V. Karlsen May 12 '11 at 21:21
  • Okay, sorry for writing a pointless question! – Josh M. May 12 '11 at 21:22
  • You're misunderstanding me. The question wasn't pointless, but there's no point in trying to rewrite the question to something else just because you didn't like the answer you got. The original question was good, but unfortunately it can't be done without resorting to reflection. That's the only answer you will get, although you will get various quantities of information with it. However, then rewriting the question to say "what if", changes the whole thing. Stack Overflow is not the best place to ask "what if my compiler could think" type of questions. There's no *right* answer. – Lasse V. Karlsen May 12 '11 at 21:30
  • I wasn't trying to rewrite the question, just clarify it. I know this isn't currently possible, I was just posing a general "what if" type of question. – Josh M. May 13 '11 at 00:54

4 Answers4

4

Because that is the definition of the constraint. It's a bit like asking why does T : class require that T be a reference type. It's true by definition.

Additionally, if it weren't a public constructor, what would be the point of the constraint? The class receiving the type parameter T wouldn't be able to call the constructor if it weren't public.

jason
  • 236,483
  • 35
  • 423
  • 525
  • Yes, I realize that "it is what it is." I'm asking why it couldn't be protected. `where T : class` is not the same at all. That constraint is very specific because it has to be. The `new()` constraint is overly-specific IMO because the generic class is able to access protected members of the derived class, including its constructor. – Josh M. May 12 '11 at 20:44
  • @Josh M. The only way Singleton would be able to access a protected constructor on T would be if Singleton inherited from T - in which case, there'd be no point using generics. – reavowed May 12 '11 at 20:54
  • I know, it's more of a theoretical question, I understand why it doesn't work that way. I was eluding to "what if a generic parent class could access the generic type's protected members?" – Josh M. May 12 '11 at 21:13
  • If a generic parent class could access the generic type's protected members, then you could write the code like you've shown, but you already knew that. What is your *actual* question here? Your question is exactly the same as this: I want to do X, but X is not possible. What if X was possible, could I do X then? ... uhm ... Yes? – Lasse V. Karlsen May 12 '11 at 21:33
  • I had to -1 this answer, as - it isn't really an answer (my apologies!). I just ran in to this myself, where both the class and the class with the generic-type definition and the `new()` constraint were in the same assembly. I can understand this failing "cross-assembly", but not for classes in the same assembly. The point of the constraint still makes perfect sense, as the class receiving the type parameter (in my case) resides in the same assembly. – Moo-Juice Aug 27 '14 at 17:36
2

You can call a protected constructor using reflection. However this should raise warning signs that you are doing something you are not supposed to. In most cases, you should be able to avoid a singleton and use dependency injection instead. If that doesn't work either, you can use something like the ambient context pattern (see my answer here).

Community
  • 1
  • 1
Can Gencer
  • 8,822
  • 5
  • 33
  • 52
1

.NET would not know that you don't want to accept

class OnlyOneOfMe : Singleton<Other>

as a valid class. Since it is actually valid it will try to make the class and needs a public Other constructor.

Jan-Peter Vos
  • 3,157
  • 1
  • 18
  • 21
0

If the constructor were protected, Singleton wouldn't be able to call it.

And I'd avoid implementing the singleton pattern like that anyway, even if I could. It's messy - what if you wanted a singleton class that inherits from an abstract one?

reavowed
  • 322
  • 1
  • 8