Hi,
I think you're confusing yourself with some of the history. Let's take a
look at this from scratch.
Actually, I don't think I'm confused here at all.
I put some more thought into just to be sure
<snip>
(I've snipped the C++ example because I don't know C++)
Back to C#. The same as in my previous email:
class A<Q<>> where Q<T> : IQueue<T>
{
...
new Q<int>();
new Q<System.Windows.Window>();
...
}
Now if I create a generic Queue class, I can pass it to A, which uses it
to
create a variety of typed queues.
new A<MyQueue<>>()
I can see what you're trying to accomplish, but I just don't think that it's
possible for the C# compiler to work like that and I believe, as I've
already stated, there are better ways.
My understanding is that you want to be able to create multiple instances of
Q, a generic argument constrained to be a generic type itself, explicitly
typed inside the definition of class A.
To elaborate on your example, inside A:
void DoSomething()
{
Q<int> iq = new Q<int>();
Q<long> lq = new Q<long>();
}
So, in essence, you're trying to doing something like this:
class A<Q, T> where Q : IQueue<T> where T : int OR long
In other words, you're explicitly defining what T's domain should be and
expecting that the compiler will infer this from your code, whether or not
any given T is assignable to any other T. The compiler would have to locate
all of your references to Q in the class definition of A, and acknowledge
how you've typed T each time (and this is before A has any concrete
implementations - it's still just A's definition).
Once you try to create an implementation of A by typing a variable as
follows, the compiler would have to ensure that T's domain doesn't conflict
with the specified generic type:
(note that you couldn't specify MyQueue<> since it's not concrete, it's
another generic type)
If MyQueue is defined as follows then the compiler would have to raise an
error since the typed domain of T in A's class definition conflicts with
MyQueue<T>'s constraints on its own T:
class MyQueue<T> where T : class
Or, if MyQueue has a differing number of generic arguments then the compiler
would have to raise an error as well.
All because you've defined T in A's definition before the compiler even knew
what Q, and therefore T, was going to be. So we'll assume that the compiler
will infer multiple definitions for T from the source code (T's domain).
Currently, both the compiler and the runtime, AFAIK, expect T to be typed as
a single type per implementation of A<Q>. In order for the above to work,
reflection would have to be extended somehow to allow generic reflection
into any given implementation of A so that Q can be realized as an array of
Types inferred from A's class definition. Therefore, this wouldn't just be
a compiler feature, but would require metadata for the runtime as well.
And since int and long are not assignable to one another, the compiler could
not allow the explicit use of T within A's class definition like it could
with Q.
So what you're left with, if it did actually compile, would be a generic
class (A) that uses two explicit interfaces for int and long, hard-coded as
such, while constraining Q to be any conforming generic implementation;
however, you could only use the contract defined by IQueue<T> anyway even
though T can no longer be specified by consumers. All of that and it's
still not doing anything that the following doesn't accomplish, in a clearer
manner too IMO:
class QInt32 : IQueue<int> {}
class QInt64 : IQueue<long> {}
class A<Q1, Q2>
where Q1 : IQueue, new() // note: non-generic interfaces
where Q2 : IQueue, new()
{
void DoSomething()
{
Q1 anyQ1 = new Q1();
Q2 anyQ2 = new Q2();
// here, you could work on anyQ1 and anyQ2 using the
// IQueue interface, which is the only thing that the compiler
// would allow even in your examples as well
}
}
If you want more than two generic queues to be encapsulated by a generic
class, I'd say that a better design pattern is probably in order anyway.
Have I missed anything important? If you still feel like it would be
possible (and more useful than my solution above) then please elaborate with
some examples.
<snip>