8
votes

Pourquoi cette déclaration de classe C # compile-t-elle?

Cette question est vraiment inutile, mais je suis juste curieux:

ceci: xxx

compile, mais donne un avertissement

Bien que cela: xxx

ne compile pas. Juste hors de curiosité, y a-t-il une raison pour cela?


3 commentaires

Je donnerais une réponse, mais pour une raison quelconque, je pense que JS en aurait un meilleur. Hmm.


Apparemment, JS hiérarchise donc à thre thref_priority_below_normal - rapide tout le monde obtient vos réponses pendant que vous le pouvez toujours!


+1 Bonne question, je n'ai même jamais rencontré cette cause que je n'ai même jamais pensé à faire ça ... parce que ça n'a aucun sens!


9 Réponses :


12
votes

virtuel est utilisé pour déclarer un Méthode / Propriété "Nursature-capable".

scellé est utilisé pour déclarer que la classe ne peut pas être héritée de.

Donc, une méthode virtuelle dans une classe scellée ne pourrait jamais être remplacée, car la classe ne pourrait jamais être héritée. Cela n'a pas de sens.

Protégé affecte l'accès à un membre , il ne le déclare pas "remplaçable" comme le fait de la virtuelle (bien qu'il soit souvent utilisé de cette manière) et n'est donc pas contradictoire.


11 commentaires

Oui, je comprends ça. Avis que je n'ai pas demandé "pourquoi cela ne compile pas" plutôt que j'ai demandé pourquoi cela compilait-il. La même manière virtuelle n'a pas de sens dans une classe scellée, protégée ne voit pas ce que je dis?


Je pense Le OP réalise que scellé ne donne pas de sens particulier avec virtuel ou avec protégé . Il se demande pourquoi un article "sans sens" est autorisé, tandis qu'un autre n'est pas.


@ 280z28 Je suis d'accord ... Nous avons besoin de Skeeter pour nous expliquer cela.


C'est environ 3 heures du matin au Royaume-Uni, alors Jon est très probablement endormi. Vous devrez attendre jusqu'à l'aube ...


Non seulement le CLI autorise non seulement les types scellés à déclarer de nouveaux membres virtuels, mais permettent d'appeler des méthodes non virtuelles avec le Callvirt IL. Tout ce que nous parlons ici sont C # "Limiter" des choses où il est logique de faire, car le code d'octet sous-jacent n'applique pas.


Non seulement cela n'a pas de sens, c'est aussi impossible. Scellé évite explicitement la surcharge d'un appel de fonction virtuelle (msil 'appelant' vs 'Callvirt').


@cfeduke: scellé signifie que le compilateur peut utiliser appel , cela ne signifie pas que cela doit.


Le CLI n'est pas responsable de l'application des règles linguistiques. Vous pourriez faire une corrobie CIL si vous le souhaitez.


@Kevin: La CLI applique de nombreuses choses sur les méthodes virtuelles. Par exemple, ils ne peuvent pas être statiques et ils ne peuvent pas être constructeurs. De plus, des méthodes abstraites et scellées doivent être virtuelles.


@ 280Z28: Oui, mais cela n'applique pas les règles C #. Les choses sont un peu confondues parce que c # / CLI a évolué ensemble, mais simplement parce que c # est en application quelque chose ne signifie pas que le CLI fait. C'est ce que j'essaie de transmettre avec mon commentaire précédent.


Protégé contrôle également l'accès de l'extérieur de la classe. Certes, vous pourriez avoir le même comportement en faisant de la CTOR privée (c'est pourquoi vous obtenez l'avertissement), mais le point principal est-il réellement une différence. Virtual n'a pas d'autre effet que de contracter directement scellé.



4
votes

Je ne peux pas voir une bonne raison pour cela. Le MyMethod protégé peut être appelé de myClass, mais ne sera jamais appelé à partir d'une classe dérivée (car myClass est scellé). La version virtuelle est également autorisée à être appelée directement à partir de myClass, mais il est illégal que la méthode d'avoir une substitution, car vous ne pouvez pas dériver une classe de myClass ...


0 commentaires

2
votes

Une classe scellée peut avoir des membres protégés par héritage. Lorsqu'une méthode fait partie d'une classe, peu importe la manière dont cette méthode est arrivée.

Dans le premier cas, avec la méthode protégée sur la classe scellée, elle est la même que si la classe scellée a hérité d'une méthode protégée. Donc il compile.

Par curiosité, quel est exactement l'avertissement donné?


1 commentaires

L'avertissement est: "AVERTISSEMENT CS0628: 'SimpleTestapp.class1.foo ()': Nouveau membre protégé déclaré en classe scellée."



1
votes

Une classe scellée ne peut pas être sous-classée, donc virtuelle n'est pas une option. Ainsi une erreur.

Ce premier est un peu idiot mais valide, donc avertissement.


0 commentaires

2
votes

L'erreur est:

CS0549: "Fonction" est un nouveau membre virtuel de la classe "classe" scellée.

Tout d'abord, malgré le fait qu'il n'a pas vraiment de sens d'inclure le nouveau protégé ou des membres virtuels dans un scellé classe , le CLI¹ le permet. La CLI permet également d'appeler des membres d'une classe scellée à l'aide de l'instruction CALLVIRT IL, même si un compilateur pourrait le remplacer librement avec l'instruction appel .

Actuellement, je ne trouve rien dans l'ECMA-334 (spécification de langue C #) qui nécessite le compilateur émettre l'erreur ci-dessus. Il semble que la mise en œuvre de Microsoft ait ajouté l'erreur simplement parce qu'il n'a pas de sens d'inclure de nouveaux membres virtuels dans une classe scellée.

¹La CLI est une machine virtuelle et le compilateur C # émet un code octet qui l'exécute. Presque tout concept illégal dans la CLI est également illégal dans C # pour cette raison - mais c'est un cas où c # fait un peu plus (pas que c'est un problème).

Edit: il semble que les postes d'être marqués expliquent pourquoi il n'a pas de sens écrire du code comme celui de l'OP. Mais sur quelle règle a fait une erreur de compilateur, ils semblent avoir tort.


0 commentaires

0
votes

Je suppose que le compilateur fait quelques optimisations avec des classes scellées impossibles si vous avez une méthode virtuelle déclarée - "Ne pas avoir de table de table" semble un candidat probable.

C'est juste une supposition, cependant.


0 commentaires

4
votes

La seule raison à laquelle je peux penser est que parfois vous auriez besoin d'écrire des méthodes protégées pour remplacer d'autres méthodes protégées. La langue pourrait a été conçue pour permettre à ceci: xxx

mais pas ceci xxx

mais cela pourrait avoir été considéré comme un peu difficile à suivre - c'est l'absence de de la substitution qui le rend inutile, alors que dans le cas de xxx

C'est la présence de virtuel qui est inutile. La présence de quelque chose de "faux" est probablement plus facile à comprendre que l'absence de quelque chose d'utile.

Dans ce cas, être virtuel peut également avoir des conséquences sur la performance, alors que la fabrication de quelque chose de protégeant au lieu de privé n'a probablement pas - C'est donc un peu plus sévère.

Ce sont simplement des devinettes, bien que nous sommes vraiment chanceux, Eric Lippert donnera une réponse plus définitive. C'est celui que tu veux, pas moi :)

meilleure réponse: Traitez les avertissements comme des erreurs et ils sont de toute façon équivalente;)


5 commentaires

OOH, bon point, je n'ai pas pensé à l'affaire où la classe scellée en question est héritée d'une base et remplace un membre protégé. Cela pourrait très bien être une raison. En fait, j'ai envoyé un courriel eric hier soir, et il a répondu dire qu'il va regarder et me revoir. Je vais garder cette question ouverte jusqu'à ce qu'il soit. Merci Jon.


Hey, je devine aussi aussi, les gars. La conception de la langue indique que la décision de faire introduire une méthode virtuelle dans un type scellé une erreur a été effectuée le 18 octobre 1999, mais ne donne aucune justification de la décision. Je peux trouver nulle part dans les notes qui justifient pourquoi introduire un nouveau membre protégé devrait être légal. Ma meilleure estimation: c'était probablement simplement une surveillance dans la première version, puis il est devenu un changement de rupture pour le réparer jamais.


@ Scientifique: par intérêt, où est-ce dans la spécification? Il ne semble pas être dans la partie introductive de 10.6 qui répertorie les règles de combinaisons valides de modificateurs. Je pensais trouver la règle et voir ensuite si cela est mentionné dans l'une des spécifications annotées ... et maintenant je ne trouve pas la règle. Je ne peux pas le voir dans 10.6.3 non plus.


Euh .... Je ne peux pas le trouver non plus. Il était clair que cela visait à entrer dans la spécification, la règle est là dans les notes. J'ajouterai un autre point sur notre longue liste d'omissions de la spécification. Merci de l'avoir apporté à mon attention.


@ERIC, pourrait-il s'agir d'une question de problèmes de mise en œuvre influençant les décisions de conception? Il semble un peu étrange car les classes de base d'une classe scellée peuvent avoir des méthodes virtuelles, mais la classe scellée elle-même ne peut pas. Avec cela, il aurait besoin de garantir que toutes les méthodes virtuelles sont remplies ... * (mais, je concède que c'est un peu stupide à la recherche de lire virtuel ou protégé dans une classe scellée.) *



0
votes

comme scellé Lorsqu'il est appliqué à une classe, le modificateur scellé empêche d'autres classes de les héritiner. Code>

Ici, j'essaie de vous expliquer un par un: P>

public sealed class MyClass
{
   public virtual void MyMethod(){}
}


0 commentaires

0
votes

déclarer qu'un nouveau membre protégé implique une intention de partager ce membre avec des classes descendantes. Une classe scellée ne peut pas avoir des descendants, la déclaration d'un nouveau membre protégé est un peu d'oxymoron, comme déclarant une nouvelle méthode virtuelle dans une classe scellée.

Tant pourquoi Virtual produit une erreur lorsqu'il est protégé ne produit qu'un avertissement, je ne peux que spéculer que cela a pour but de faire avec le fait que de nouvelles méthodes virtuelles nécessitent que le compilateur de construire des structures de données pour le type (un circuit équitable), tandis que De nouveaux membres protégés n'ont qu'un jeu d'indicateur d'accès - aucune nouvelle structure de données. Si le compilateur est interdit de créer un circule pour une classe scellée, que devrait-il faire si elle rencontre une nouvelle méthode virtuelle? Échouer la compilée. Une nouvelle méthode protégée dans une classe scellée est inutile mais n'a pas nécessité le compilateur de s'aventurer dans un territoire interdit.


0 commentaires