1 votes

Est-il courant (ou encouragé) de surcharger une fonction pour accepter IEnumerable<T>, ICollection<T>, IList<T>, etc.?

MODIFIER:

Des réponses données, il m'est plutôt clair comment la conception que je demande ci-dessous devrait en fait être implémentée. Avec ces suggestions à l'esprit (et en réponse à un commentaire indiquant poliment que mon code exemple ne compile même pas), j'ai modifié le code suivant pour refléter ce que semble être le consensus général. La question qui reste peut ne plus avoir de sens à la lumière du code, mais je la laisse telle quelle pour la postérité.


Supposons que j'ai trois surcharges d'une fonction, une prenant IEnumerable, une prenant ICollection, et une prenant IList, quelque chose comme ce qui suit:

public static T GetMiddle(IEnumerable values) {
    IList list = values as IList;
    if (list != null) return GetMiddle(list);

    int count = GetCount(values);

    T middle = default(T);
    int index = 0;

    foreach (T value in values) {
        if (index++ >= count / 2) {
            middle = value;
            break;
        }
    }

    return middle;
}

private static T GetMiddle(IList values) {
    int middleIndex = values.Count / 2;
    return values[middleIndex];
}

private static int GetCount(IEnumerable values) {
    // si les valeurs sont en fait une ICollection (par exemple, List),
    // nous pouvons obtenir le nombre assez bon marché
    ICollection genericCollection = values as ICollection;
    if (genericCollection != null) return genericCollection.Count;

    // même pour ICollection (par exemple, Queue, Stack)
    ICollection collection = values as ICollection;
    if (collection != null) return collection.Count;

    // sinon, nous devons compter les valeurs nous-mêmes
    int count = 0;
    foreach (T value in values) count++;

    return count;
}

L'idée ici est que, si j'ai un IList, cela facilite mon travail; d'autre part, je peux toujours faire le travail avec un ICollection ou même un IEnumerable; l'implémentation pour ces interfaces n'est tout simplement pas aussi efficace.

Je n'étais pas sûr que cela fonctionnerait même (si le runtime serait capable de choisir une surcharge basée sur le paramètre passé), mais je l'ai testé et il semble que oui.

Ma question est : y a-t-il un problème avec cette approche auquel je n'ai pas pensé ? Alternativement, cette approche est-elle en fait bonne, mais y a-t-il une meilleure façon de l'accomplir (peut-être en essayant de caster l'argument values en un IList d'abord et en exécutant la surcharge plus efficace si le cast fonctionne) ? Je suis juste intéressé à savoir ce que les autres pensent.

0voto

csharptest.net Points 16556

Généralement, lors de la conception des interfaces, vous souhaitez accepter un type de "moindre dénominateur commun" pour les arguments. Pour les types de retour, il s'agit d'un sujet de débat. Je pense généralement que la création des surcharges ci-dessus est exagérée. Son plus gros problème est l'introduction de chemins de code inutiles qui doivent maintenant être testés. Il vaut mieux avoir une méthode qui effectue l'opération d'une seule manière et fonctionne 100% du temps. Avec les surcharges ci-dessus, vous pourriez avoir une incohérence de comportement sans même vous en rendre compte, ou pire encore, vous pourriez introduire accidentellement un changement dans l'une et pas dans les autres copies.

Si vous pouvez le faire avec IEnumerable, utilisez-le, sinon utilisez l'interface minimale nécessaire.

0voto

4pie0 Points 481

Non. C'est certainement inhabituel.

Quoi qu'il en soit. Puisque IList hérite de ICollection et IEnumerable, et ICollection hérite de IEnumerable, votre seule préoccupation serait les performances dans les types IEnumerable.

Je ne vois aucune raison de surcharger la fonction de cette manière, en fournissant des signatures différentes pour obtenir exactement le même résultat et en acceptant exactement les mêmes types en tant que paramètre (peu importe si vous avez un IEnumerable ou IList, vous pourriez le passer à l'une quelconque des trois surcharges); cela causerait juste de la confusion.

Quand vous surchargez une fonction, c'est juste pour fournir un moyen de passer un type de paramètre différent que vous ne pouvez pas passer à la fonction s'il n'avait pas cette signature.

Ne pas optimiser à moins que ce ne soit vraiment nécessaire. Si vous souhaitez optimiser, faites-le en coulisses. Vous ne prétendriez pas que quelqu'un utilisant votre classe soit conscient de cette "optimisation" afin de décider quelle signature de méthode utiliser, n'est-ce pas?

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