Ce qui suit est une question d'entrevue. J'ai trouvé une solution, mais je ne sais pas pourquoi cela fonctionne.
Question:
Sans modifier la Sparta
classe, écrivez du code qui rend le MakeItReturnFalse
retour false
.
public class Sparta : Place
{
public bool MakeItReturnFalse()
{
return this is Sparta;
}
}
Ma solution: (SPOILER)
public class Place
{
public interface Sparta { }
}
Mais pourquoi Sparta
en MakeItReturnFalse()
référence à la {namespace}.Place.Sparta
place de {namespace}.Sparta
?
Réponses:
Fondamentalement, parce que c'est ce que disent les règles de recherche de noms. Dans la spécification C # 5, les règles de dénomination pertinentes se trouvent dans la section 3.8 («Noms d'espaces de noms et de types»).
Les deux premières puces - tronquées et annotées - se lisent:
Donc, ce dernier point est ce qui ramasse la
Sparta
classe si la première puce ne trouve rien ... mais lorsque la classe de basePlace
définit une interfaceSparta
, elle est trouvée avant que nous considérions laSparta
classe.Notez que si vous faites du type imbriqué
Place.Sparta
une classe plutôt qu'une interface, il compile et retourne toujoursfalse
- mais le compilateur émet un avertissement car il sait qu'une instance deSparta
ne sera jamais une instance de la classePlace.Sparta
. De même, si vous conservezPlace.Sparta
une interface mais créez laSparta
classesealed
, vous recevrez un avertissement car aucuneSparta
instance ne pourra jamais implémenter l'interface.la source
Sparta
classe d' origine ,this is Place
retournetrue
. Cependant, l'ajoutpublic interface Place { }
à laSparta
classe entraînethis is Place
le retourfalse
. Ça me fait tourner la tête.Place
comme interface.Lors de la résolution d'un nom à sa valeur, la "proximité" de la définition est utilisée pour résoudre les ambiguïtés. Quelle que soit la définition «la plus proche», c'est celle qui est choisie.
L'interface
Sparta
est définie dans une classe de base. La classeSparta
est définie dans l'espace de noms contenant. Les choses définies dans une classe de base sont "plus proches" que les choses définies dans le même espace de noms.la source
Belle question! Je voudrais ajouter une explication un peu plus longue pour ceux qui ne font pas C # quotidiennement ... parce que la question est un bon rappel des problèmes de résolution de noms en général.
Prenez le code d'origine, légèrement modifié de la manière suivante:
return this is Sparta
).Athena
dans lePlace
superclasse pour illustrer la résolution des noms d'interface.this
tel qu'il est lié dans laSparta
classe, juste pour que tout soit très clair.Le code ressemble à ceci:
Nous créons maintenant un
Sparta
objet et appelons les trois méthodes.Le résultat que nous obtenons est:
Cependant, si nous modifions la classe Place et définissons l'interface Sparta:
alors c'est ceci
Sparta
- l'interface - qui sera disponible en premier pour le mécanisme de recherche de nom et la sortie de notre code changera en:Nous avons donc effectivement foiré la comparaison de type dans la
MakeItReturnFalse
définition de fonction en définissant simplement l'interface Sparta dans la superclasse, qui se trouve d'abord par la résolution de nom.Mais pourquoi C # a-t-il choisi de prioriser les interfaces définies dans la superclasse dans la résolution de noms? @JonSkeet le sait! Et si vous lisez sa réponse, vous obtiendrez les détails du protocole de résolution de noms en C #.
la source