C# Naked type constraints

791 views Asked by At

In "C# 6.0 in a Nutshell" there is an example of naked type constarint usage:

class Stack<T>
{
  Stack<U> FilteredStack<U>() where U : T {...}
}

Honestly, I don't understand why I should use this constraint here. If I'll remove it and change U to T, result will be the same. So what's the point?

Thank you.

3

There are 3 answers

0
15ee8f99-57ff-4f92-890c-b56153 On BEST ANSWER

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);
    }
}
0
Titian Cernicova-Dragomir On

If you have a Stack<Animal> you can use FilteredStack<Dog> to get a Stack<Dog>. The point is that you want to be sure that the U passed to FilteredStack is a type derived from T but not necessarily T

0
Vijayanath Viswanathan On

Generic constraint is using to restrict the access of Generic types, functions etc.

where U : T means only those classes inherits from U would be able to access the function FilteredStack(). Object of those class which is not inherited from U should not be able to access FilteredStack() and it will give a compilation error. This is the whole purpose of type safing