2016-09-07 7 views
1

Je suis Tring à faire:Ne peut pas masquer l'erreur du compilateur membre hérité

public abstract class Base 
{ 
    public abstract Task Execute(); 
} 

public abstract class Concrete<T> : Base where T : class 
{ 
    new public abstract Task<T> Execute(); 
} 

Mais pour une raison quelconque, je reçois l'erreur du compilateur:

CS0533 « Concrete.Execute() » Cuirs héritée membre abstrait 'Program.Base.Execute()

J'ai caché beaucoup de membres dans le passé, mais je n'ai jamais rencontré cette affaire et je suis assez perplexe ici. J'ai passé beaucoup de temps sur MSDN et le web mais je n'ai rien trouvé de ce comportement.

J'apprécierais vraiment tout aperçu sur la question.

Voici the fiddle.

+0

Même s'il manque un 'virtual',' override' a fonctionné pour moi à la place de 'new'. Toutefois, le problème est que vous modifiez le type de retour lorsque vous masquez la valeur de base. Vous devrez changer le nom ou faire en sorte que la sous-classe renvoie la valeur «Task». – Max

+0

@mason Je supposais que le compilateur ramasserait la définition sur le béton (J'ai vu que le type de retour est correctement déduit par IntelliSense quand je fais cela - malgré l'erreur du compilateur). Donc, si je vous comprends bien, le problème est qu'il n'est pas possible de changer la signature lorsqu'on se cache avec 'new'? (J'ai le sentiment que je l'ai fait dans le passé, je me trompe peut-être) – reddy

+0

@mason voici un exemple de compteur, la signature peut être modifiée avec des propriétés: https://dotnetfiddle.net/B4IkHj il semble que la question est lié à des méthodes/membres abstraits en quelque sorte – reddy

Répondre

4

Le problème est que la méthode de base est abstract. Une classe héritant de Concrete<T> doit avoir outrepasser , mais ne peut pas l'ignorer, car il est masqué par Derived<T>.Execute(). Donc, Concrete<T> serait une classe abstract qui ne peut avoir aucune implémentation (du moins pas en C#), donc elle serait inutile. Ainsi, le compilateur C# ne vous laisse pas l'écrire.

Si Base était une interface, vous pouvez contourner ce problème en utilisant une implémentation d'interface explicite. Mais il n'y a rien comme l'implémentation explicite de la classe de base, donc je ne pense pas qu'il y ait moyen d'avoir ce genre de code, du moins pas sans renommer l'une des deux méthodes.

+0

Je viens de le réaliser et je suis revenu à cet onglet pour le dire - mais tu l'as dit beaucoup mieux que je l'aurais fait. Je pensais que: si quelqu'un référence une variable 'Concrete' comme un type' Base', le membre abstrait serait indéfini. Merci beaucoup. – reddy

1

De MSDN:

Une déclaration de méthode abstraite introduit une nouvelle méthode virtuelle, mais ne fournit pas une mise en œuvre de cette méthode. Au lieu de cela, classes dérivées non abstraites sont tenus de fournir leur propre mise en œuvre en remplaçant cette méthode

Eh bien, la raison de cette erreur est la façon dont les abstractions fonctionnent en C#, l'abstraction peut être héritée, il peut être mis en œuvre, mais il ne peut pas être caché ou remplacé par une autre abstraction.

De plus, considérez le code:

public abstract class Base 
{ 
    public abstract Task Execute(); 
    public abstract Task<int> Execute(); 
} 

Cela ne compile pas, parce que:

Type 'base' définit déjà un membre appelé 'Exécuter' avec les mêmes types de paramètres

Alors pourquoi cela devrait-il fonctionner lorsque nous déplaçons la seconde méthode vers une classe abstraite dérivée?

+0

Cette classe: 'public class Base { public Tâche Exécuter() => null; public Tâche Execute() => null; } 'ne compile pas avec la même erreur que votre' Base'. Mais ces deux classes font: 'public class Base { public Tâche Execute() => null; } classe Dérivée: base { public nouveau Tâche Execute() => null; } '. Donc cette partie de votre raisonnement n'est pas correcte: une telle erreur peut être corrigée en déplaçant la méthode vers une classe dérivée. – svick