2017-08-30 3 views
3

Dans "C# 6.0 in a Nutshell" il y a un exemple de type nu usage de constarint:C# contraintes de type nu

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

Honnêtement, je ne comprends pas pourquoi je devrais utiliser cette contrainte ici. Si je l'enlève et change U en T, le résultat sera le même. Alors, quel est le point?

Merci.

Répondre

8

Le point est que U peut être de tout type qui est une sous-classe de T et le Stack que nous obtenons est une pile de ce type, pas de T. Par conséquent, les éléments qui y sont ajoutés doivent être de type U et les éléments que vous en récupérez sont garantis U s'ils ne sont pas NULL. Toutes les joies et les peines familières de la vérification de type à la compilation.

Les éléments du Stack<T> peuvent être de type T ou de toute sous-classe de T. Le nom de cette méthode suggère qu'il renvoie une pile qui contient uniquement les éléments de la pile parent qui appartiennent à une sous-classe particulière. Une fois que vous garantissez que tous les éléments de la nouvelle pile sont du type plus spécialisé, c'est beaucoup plus utile si c'est le type de la nouvelle pile.

Voici un exemple d'une manière extravagante artificielle (clairement, cette classe « stack » ne fait pas vraiment quoi que ce soit une pile ne, mais pour notre exemple, il n'a pas besoin de):

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); 
    } 
} 
3

Si vous avez un Stack<Animal> vous pouvez utiliser FilteredStack<Dog> pour obtenir un Stack<Dog>. Le point est que vous voulez être sûr que le U passé à FilteredStack est un type dérivé de T mais pas nécessairement T

0

contrainte générique utilise pour restreindre l'accès des types génériques, fonctions, etc.

où U : T signifie que seules les classes héritées de U pourront accéder à la fonction FilteredStack(). L'objet de ces classes qui n'est pas hérité de U ne devrait pas pouvoir accéder à FilteredStack() et cela donnera une erreur de compilation. C'est tout le but de la sécurité de type