web-dev-qa-db-fra.com

Pourquoi utiliser une méthode générique avec une contrainte de type au lieu du type lui-même?

Dans une autre question StackExchange, j'ai remarqué quelqu'un utilisant ce prototype:

void DoSomething<T>(T arg) where T: SomeSpecificReferenceType
{
    //Code....
}

En gardant à l'esprit qu'il n'y a qu'une seule contrainte de type (SomeSpecificReferenceType), quelle est la différence et l'avantage de l'écrire comme ça, au lieu de simplement:

void DoSomething(SomeSpecificReferenceType arg)
{
    //Code....
}

Dans les deux cas, arg sera soumis à une vérification de type à la compilation. Dans les deux cas, le corps de la méthode peut s'appuyer en toute sécurité sur la connaissance que arg est (ou est un descendant) d'un type spécifique qui est connu au moment de la compilation.

Est-ce le cas d'un développeur trop zélé qui apprend les génériques avant d'apprendre l'héritage ordinaire? Ou y a-t-il une raison légitime pour qu'une signature de méthode soit écrite de cette façon?

14
John Wu

Est-ce le cas d'un développeur trop zélé qui apprend les génériques avant d'apprendre l'héritage ordinaire?

Oui, probablement.

Ou y a-t-il une raison légitime pour qu'une signature de méthode soit écrite de cette façon?

Peut-être. En général, cela aurait plus de sens s'il y avait une valeur de retour impliquant T, ou un autre paramètre utilisant T.

Mais, il est possible que les éléments internes du code utilisent T (peut-être comme argument d'un sérialiseur?) Et besoin pour utiliser spécifiquement T et non la classe de contrainte . Vous verrez parfois que lorsque la contrainte est une interface associée à la contrainte new et que les entrailles de la méthode créent Ts pour une raison quelconque.

Donc, bien qu'il soit rare de voir la version de contrainte nécessaire, il y a des moments où elle l'est. Et il est toujours possible que la méthode tilisée en ait besoin, mais ce n'est plus le cas et le développeur l'a laissée telle quelle pour ne pas introduire de changement de rupture.

13
Telastyn

Je pense que je me souviens avoir tapé une réponse contenant ceci.

A cette époque, la raison était la suivante:
(Le code peut être différent. Juste pour illustrer l'une des raisons possibles pour lesquelles il existe une contrainte sur le paramètre type dans une méthode générique.)

class SomeSingleton
{
    static Dictionary<Type, List<object>> staticTypeSpecificList;
    public void AddObjectToList<T>(T t) where T : SomeCommonThing
    {
        Type tt = t.GetType();
        List<object> list;
        if (!staticTypeSpecificList.TryGet(tt, out list))
        {
            list = new List<object>();
            staticTypeSpecificList.Add(tt, list);
        }
        list.Add(t);
    }
}

Fondamentalement, le code entre lui-même dans les manipulations de type de codage manuel. Il peut également être mélangé à des éléments de réflexion.

Par exemple, en utilisant Method<T>(T arg) where T : ..., on peut remplacer arg.GetType() par typeof(T). Cependant, je ne sais pas si ce choix est bon ou mauvais.

Je suppose que ce n'est qu'un exemple de l'auteur (peut-être moi ou quelqu'un d'autre) ne réfléchissant pas soigneusement à toutes les possibilités de codage, tout en se concentrant trop sur une question/un problème différent.

1
rwong