56 votes

Pourquoi n'y a-t-il pas de variance générique pour les classes en C # 4.0?

Si nous l’avons pour les interfaces, pourquoi ne l’avons-nous pas également pour les classes? Quel serait le problème que nous rencontrerions en l'utilisant?

Merci

113voto

Eric Lippert Points 300275

Supposons que vous ayez une classe C<T> qui a été covariants en T. Ce qui pourrait sa mise en œuvre ressembler? T a sortir seul. Cela signifie qu' C<T> ne peuvent pas avoir une méthode qui prend un T, un bien de type T avec un setter, ou n'importe quel champ de type T, parce que les champs sont logiquement les mêmes que les setters de propriété; T va dans.

À peu près la seule chose utile que vous pouvez construire avec un covariant de classe est quelque chose d'immuable, aussi loin que T est concernée. Maintenant, je pense qu'il serait génial d'avoir covariante immuable listes et piles et autres joyeusetés qui ont été les types de classes. Mais cette fonctionnalité n'est pas si évidemment génial qu'il serait justifier clairement le massif des dépenses en rendant le système de type nativement en charge des covariants immuable types de classe.

Un commentaire ci-dessus, a demandé un exemple de cas où cela serait utile. Considérons le schéma suivant:

sealed class Stack<out T>
{
    private readonly T head;
    private readonly Stack<T> tail;
    public T Peek() { return head; }
    public Stack<T> Pop() { return tail; }
    public Stack(T head, Stack<T> tail)
    {
        this.tail = tail;
        this.head = head;
    }
}
static class StackExtensions
{
    public static Stack<T> Push<T>(this Stack<T> tail, T head) 
    {
        return new Stack<T>(head, tail);
    }
    public static bool IsEmpty<T>(this Stack<T> stack)
    {
        return stack == null;
    }
}

Supposons que vous avez eu covariante des classes. Maintenant, vous pouvez dire

Stack<string> strings = null;
strings = strings.Push("hello");
strings = strings.Push("goodbye");
Stack<object> objects = strings;
objects = objects.Push(123);

Et hey, nous avons juste poussé un entier sur un tapis de cordes, mais tout fonctionnait très bien! Il n'y a aucune raison pourquoi cela ne pouvait pas être typesafe. Une opération qui constituerait une violation de la sécurité de type sur une structure de données mutable peut être en toute sécurité covariante sur est immuable la structure de données.

3voto

Ian Ringrose Points 19115

L' .NET de l'équipe avec le C# et VB.NET l'équipe a des ressources limitées, le travail qu'ils ont fait sur la covariance et la contravariance résout la plupart du monde réel problème. Type de systèmes sont très complexes à obtenir le droit – une solution qui fonctionne dans 99,9999% des cas, n'est pas assez bon si elle conduit à la contamination de code dans les autres cas.

Je ne pense pas que le coût/temps de soutenir la covariance et la contravariance spécifications (par exemple, "en"/"out") sur les méthodes de la classe est d'une assez grande valeur. Je vois très rares cas où ils seraient utilisables – en raison de l'absence de multiplier l'héritage de classe.

Préférez-vous l'avais attendu 6 mois pour .net pour obtenir cette aide?


Une autre façon de penser, c'est que dans .net

  • Interfaces / délégués sont utilisés pour modéliser le conceptuel type de système d'une application
  • De classe sont utilisées pour mettre en œuvre les types ci-dessus
  • L'héritage de classe est utilisé pour réduire la duplication de code tout en faisant de la ci-dessus
  • la covariance et la contravariance est sur le conceptuel type de système d'une application

2voto

ntziolis Points 7360

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X