8 votes

Surcharge de méthodes et interface générique en C#

Je suis confus par un problème que nous avons dans notre projet. J'ai essayé de le simplifier pour reproduire l'effet :

interface IBar { }

class Bar : IBar {}

interface IFoo<T> where T : IBar { }

class Foo<T> : IFoo<T> where T : IBar { }

class Class1
{
    public void DoTheFoo<T>(T bar) where T : IBar
    {}

    public void DoTheFoo<T>(IFoo<T> foo) where T : IBar
    {}

    public void Test()
    {
        var bar = new Bar();
        var foo = new Foo<Bar>();

        DoTheFoo(bar); // works

        DoTheFoo<Bar>(foo); // works
        DoTheFoo((IFoo<Bar>)foo); // works
        DoTheFoo(foo); // complains
    }
}

Pour moi, cela semble bien, mais le compilateur se plaint sur le dernier appel, car il essaie de DoTheFoo<T>(T bar) au lieu de DoTheFoo<T>(IFoo<T> foo) et se plaint que le type d'argument ne correspond pas.

  • Lorsque je supprime la méthode DoTheFoo<T>(T bar) le dernier appel fonctionne !
  • Quand je le change en DoTheFoo<T>(Foo<T> foo) ça marche, mais je ne peux pas utiliser ça.

Il n'est pas trop difficile de contourner ce problème dans notre code actuel. Mais il est a) étrange et b) dommage que nous ne puissions pas avoir ces deux méthodes surchargées.

Existe-t-il une règle commune qui explique ce comportement ? Est-il possible de le faire fonctionner (sauf en donnant des noms différents aux méthodes) ?

7voto

Jon Skeet Points 692016

Il s'agit simplement d'une question d'inférence de type qui ne joue pas vraiment en votre faveur lorsqu'elle est combinée à la résolution de surcharge. Il est facile de résoudre ce problème en spécifiant explicitement l'argument de type - aucun cast n'est nécessaire :

DoTheFoo<Bar>(foo);

En général, je suis nerveux face aux surcharges qui prennent des types de paramètres assez différents. Souvent, le code est plus simple si vous donnez des noms différents aux méthodes. En dehors de toute autre chose, alors votre lecteurs n'ont pas besoin d'essayer d'effectuer la résolution de surcharge en même temps que l'inférence de type...

EDIT : Je crois que le problème est que la commande fonctionne comme ceci :

  • Les deux méthodes sont trouvées
  • L'inférence de type est appliquée aux deux méthodes sans valider les contraintes - donc pour la première méthode, on obtient T = Foo<Bar> et pour la deuxième méthode, nous obtenons T = Bar . Les deux méthodes sont applicables à ce stade.
  • Une résolution de surcharge est effectuée, qui décide que la première méthode est la plus spécifique.
  • Seulement après la résolution des surcharges a été effectuée est la contrainte sur les T vérifié - et cela échoue parce qu'il n'y a pas de conversion de référence à partir de Bar a IFoo .

Hay un Article du blog d'Eric Lippert expliquant pourquoi le langage est conçu de cette façon , a article de blog que j'ai écrit à ce sujet et un article que j'ai écrit sur la surcharge en général . Chacun d'entre eux peut aider ou non :)

EDIT : En laissant l'inférence de type de côté pour un moment, la raison pour laquelle la première méthode est plus spécifique est que dans un cas nous convertissons de Foo<Bar> a Foo<Bar> et dans l'autre nous convertissons de Foo<Bar> a IFoo<Bar> . Conformément à la section 7.5.3.3 de la spécification C# 5 :

Étant donné une conversion implicite C1 qui convertit une expression E en un type T1, et une conversion implicite C2 qui convertit une expression E en un type T2, C1 est une meilleure conversion que C2 si au moins une des conditions suivantes est remplie : - E a un type S et une conversion d'identité existe de S à T1 mais pas de S à T2. - ...

La conversion d'identité se fait d'un type vers lui-même, ce qui signifie que est le cas pour la première surcharge, mais n'est pas pour le second. Donc la première conversion est meilleure.

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