Problème de surcharge de la méthode C # avec une classe dérivée d’une classe abstraite générique

Je travaille sur un projet et j’ai un type abstrait générique qui prend un paramètre de type qui est lui-même dérivé du type abstrait. Si vous voulez savoir pourquoi je ferais cela, veuillez voir cette question .

J’ai rencontré un problème intéressant avec la surcharge d’une méthode dans une classe dérivée définie dans la classe abstraite. Voici un exemple de code:

public abstract class AbstractConverter where U : AbstractConvertible where T : AbstractConverter { public abstract T Convert(U convertible); } public class DerivedConvertibleConverter : AbstractConverter { public DerivedConvertibleConverter(DerivedConvertible convertible) { Convert(convertible); } public override DerivedConvertibleConverter Convert(DerivedConvertible convertible) { //This will not be called System.Console.WriteLine("Called the most derived method"); return this; } public DerivedConvertibleConverter Convert(Convertible convertible) { System.Console.WriteLine("Called the least derived method"); return this; } } public abstract class AbstractConvertible {} public class Convertible : AbstractConvertible {} public class DerivedConvertible : Convertible {} 

Dans l’exemple ci-dessus, la surcharge de Convert qui n’existe pas dans le parent abstrait (et qui est moins dérivée) est appelée. Je m’attendrais à ce que la version la plus dérivée, de la classe parente, soit appelée.

En essayant de résoudre ce problème, je suis tombé sur une solution intéressante:

 public abstract class AbstractConverter where U : AbstractConvertible { public abstract AbstractConverter Convert(U convertible); } public class DerivedConvertibleConverter : AbstractConverter { public DerivedConvertibleConverter(DerivedConvertible convertible) { Convert(convertible); } public override DerivedConvertibleConverter Convert(DerivedConvertible convertible) { System.Console.WriteLine("Called the most derived method"); return this; } public DerivedConvertibleConverter Convert(Convertible convertible) { System.Console.WriteLine("Called the least derived method"); return this; } } public abstract class AbstractConvertible {} public class Convertible : AbstractConvertible {} public class DerivedConvertible : Convertible {} 

Lorsque l’argument de type dérivé est supprimé de la classe de base, la version la plus dérivée de Convert est appelée. Je ne m’attendrais pas à cette différence, car je ne m’attendrais pas à voir l’interface de la version abstraite de Convert modifiée. Cependant, je dois me tromper. Quelqu’un peut-il expliquer pourquoi cette différence se produit? Merci beaucoup d’avance.

Dans l’exemple ci-dessus, la surcharge de Convert qui n’existe pas dans le parent abstrait (et qui est moins dérivée) est appelée. Je m’attendrais à ce que la version la plus dérivée, de la classe parente, s’appelle

Beaucoup de gens ont cette attente. Cependant, le comportement que vous observez est correct et par conception.

L’algorithme de résolution de surcharge va comme ceci. Nous dressons d’abord une liste de toutes les méthodes accessibles que vous pourriez appeler. Les méthodes qui remplacent les méthodes virtuelles sont considérées comme des méthodes de la classe qui les a déclarées, et non de la classe qui les a surchargées. Ensuite, nous filtrons ceux pour lesquels les arguments ne peuvent pas être convertis en types de parameters formels. Ensuite, nous filtrons toutes les méthodes qui sont sur tout type moins dérivé que tout type ayant une méthode applicable. Ensuite, nous déterminons quelle méthode est meilleure qu’une autre, s’il rest encore plus d’une méthode.

Dans votre cas, il existe deux méthodes applicables possibles. Celui qui utilise un DerivedConvertible est considéré comme une méthode de la classe de base et n’est donc pas aussi performant que celui qui utilise un Convertible.

Le principe ici est que le remplacement d’une méthode virtuelle est un détail d’implémentation sujet à modification, et non un indice pour le compilateur que la méthode de remplacement doit être choisie.

Plus généralement, ces fonctionnalités de l’algorithme de résolution de surcharge sont conçues pour aider à atténuer diverses versions du problème de Brittle Base Class.

Pour plus de détails sur ces décisions de conception, voir mon article sur le sujet:

http://blogs.msdn.com/b/ericlippert/archive/2007/09/04/future-breaking-changes-part-three.aspx

Lorsque l’argument de type dérivé est supprimé de la classe de base, la version la plus dérivée de Convert est appelée. Je ne m’attendrais pas à cette différence, car je ne m’attendrais pas à ce que l’interface de la version abstraite de Convert ait changé

La question est basée sur une fausse prémisse; la version la plus dérivée n’est pas appelée. Le fragment de programme est erroné et ne comstack donc pas. Aucune méthode n’est donc appelée. le programme ne s’exécute pas car il ne comstack pas.