The point is that U
can be any type that is a subclass of T
, and the Stack
you get back is a stack of that type, not of T
. Therefore, items added to it must be of type U
, and items you get back out of it are guaranteed to be U
if they're not null. All the familiar joys and sorrows of compile-time type checking.
The items in the Stack<T>
could be of type T
, or any subclass of T
. The name of that method suggests that it's returning a stack that contains only the items in the parent stack that are actually of some particular subclass. Once you're guaranteeing that all the items in the new stack are of the more specialized type, it's far more useful if that's the type of the new stack as well.
Here's a wildly contrived example (clearly, this "stack" class doesn't actually do anything a stack does, but for our example it doesn't need to):
public class A
{
public A(String s)
{
SA = s;
}
public String SA { get; set; }
}
public class B : A
{
public B(String s, string s1)
{
SA = s;
SB = s1;
}
public String SB { get; set; }
}
class Stack<T>
{
Stack<U> FilteredStack<U>() where U : T
{
return new Stack<U>(Items.OfType<U>());
}
public IEnumerable<T> Items { get { return _items; } }
public static void Test()
{
var s1 = new Stack<A>(new[] { new A("A1"), new B("B1", "Some other value") });
var s2 = s1.FilteredStack<B>();
// s2 is a strongly typed stack of type B
Console.WriteLine(s2.Items.First().SB);
}
private List<T> _items = new List<T>();
public Stack(IEnumerable<T> items) {
_items = new List<T>(items);
}
}