Reputation: 537
class Stack<T>
{
T[] items;
int index;
public delegate void StackDelegate(T[] items);
internal static void DoWork(int[] items) { }
}
class TestStack
{
public static void TestSta()
{
Stack<float> s = new Stack<float>();
Stack<int>.StackDelegate d = Stack<float>.DoWork;
}
static void Main()
{
TestSta();
}
}
}
In the code above, the non-generic delegate is defined inside a generic-class. The non-generic delegate uses a type parameter of the the containing class.
When referencing the delegate, we need to to qualify the name of the delegate type using both the containing class name where the delegate type was defined and a type argument for the type parameter of the containing class, otherwise the compiler wont be able to find the delegate.
When we reference the StackDelegate delegate using a type argument, is that the type argument used to construct the delegate?
Stack<int>.StackDelegate d = Stack<float>.DoWork;
In this case, which type is used to construct the delegate? <int>
or <float>
?
Also, is a class initialized when a nested type, say a delegate, is referenced, and if so how?
Does the following statement Stack<int>.StackDelegate d
causes the class Stack to be <int>
constructed and initialized, and then the statement Stack<float>.DoWork;
causes another construction and initialization of the class Stack. Meaning, do we get two initialized types out of the generic class stack at run time after executing this statement?
Upvotes: 2
Views: 704
Reputation: 40818
Does this mean that in order to use a nested delegate, its containing type must be initialized (in this case the generic Stack class), and the reason we need a type-parameter argument, is because without one, the containing generic class wont be able to construct into a concrete class, hence wont be able to initialize?
No, the containing type (Stack<T>
) does not need to be initialized. If you add a static constructor to Stack<T>
, then you will see that it is never called by your sample. (It will be initialized when d
is invoked) You should be aware that there are actually infinitely many nested types, one for each generic parameter type T
. The types Stack<int>.StackDelegate
and Stack<float>.StackDelegate
are completely different to the runtime.
Is this valid? And if not, why?
Yes, it is valid because the method matches the return type and signature of the delegate type. The delegate type Stack<float>.StackDelegate
takes a float[]
as a parameter and therefore incompatible with Stack<float>.DoWork
. If you wanted a different type parameter in StackDelegate
you would have to declare it like this:
public delegate void StackDelegate<U>(U[] items);
Now Stack<int>.StackDelegate<int>
is a different type from Stack<float>.StackDelegate<int>
, however these two delegate types are compatible because they have the same signature and return types.
Upvotes: 1
Reputation: 100547
Type of "DoWork" is void DoWork(int[])
(it does not use T
), so it perfectly matches StackDelegate
when T
is int
.
There is a chance that you wanted to declare DoWork
to depend on T
:
internal static void DoWork(T[] items) { }
In this case you'll get expected compile time error:
No overload for 'DoWork' matches delegate 'UserQuery.Stack.StackDelegate'
Upvotes: 0