The following is an interview question. I came up with a solution, but I'm not sure why it works.
Question:
Without modifying the Sparta
class, write some code that makes MakeItReturnFalse
return false
.
public class Sparta : Place
{
public bool MakeItReturnFalse()
{
return this is Sparta;
}
}
My solution: (SPOILER)
public class Place
{
public interface Sparta { }
}
But why does Sparta
in MakeItReturnFalse()
refer to {namespace}.Place.Sparta
instead of {namespace}.Sparta
?
300 (1/5) Best Movie Quote - This is Sparta!
This is SPARTA! is a 2007 meme that originated from a scene from the movie "300" in which Leonidas, the leader of the Spartans, kicks a persian messenger into a hole.
Gerard Butler Says Unexpected Delivery of Iconic '300' Line Made Cast Laugh. In a GQ video posted Monday, actor Gerard Butler explains when he screamed the iconic '300' line "This is Sparta!" that his army almost broke character laughing.
Gerard Butler's tense standoff with a messenger is one of the most memorable moments in 300. In the scene, his character, King Leonidas, shouts “This is Sparta!” before kicking him into a pit of darkness.
But why does
Sparta
inMakeItReturnFalse()
refer to{namespace}.Place.Sparta
instead of{namespace}.Sparta
?
Basically, because that's what the name lookup rules say. In the C# 5 specification, the relevant naming rules are in section 3.8 ("Namespace and type names").
The first couple of bullets - truncated and annotated - read:
- If the namespace-or-type-name is of the form
I
or of the formI<A1, ..., AK>
[so K = 0 in our case]:
- If K is zero and the namespace-or-type-name appears within a generic method declaration [nope, no generic methods]
- Otherwise, if the namespace-or-type-name appears within a type declaration, then for each instance type T (§10.3.1), starting with the instance type of that type declaration and continuing with the instance type of each enclosing class or struct declaration (if any):
- If
K
is zero and the declaration ofT
includes a type parameter with nameI
, then the namespace-or-type-name refers to that type parameter. [Nope]- Otherwise, if the namespace-or-type-name appears within the body of the type declaration, and
T
or any of its base types contain a nested accessible type having nameI
andK
type parameters, then the namespace-or-type-name refers to that type constructed with the given type arguments. [Bingo!]- If the previous steps were unsuccessful then, for each namespace
N
, starting with the namespace in which the namespace-or-type-name occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located:
- If
K
is zero andI
is the name of a namespace inN
, then... [Yes, that would succeed]
So that final bullet point is what picks up the Sparta
class if the first bullet doesn't find anything... but when the base class Place
defines an interface Sparta
, it gets found before we consider the Sparta
class.
Note that if you make the nested type Place.Sparta
a class rather than an interface, it still compiles and returns false
- but the compiler issues a warning because it knows that an instance of Sparta
will never be an instance of the class Place.Sparta
. Likewise if you keep Place.Sparta
an interface but make the Sparta
class sealed
, you'll get a warning because no Sparta
instance could ever implement the interface.
When resolving a name to its value the "closeness" of the definition is used to resolve ambiguities. Whatever definition is "closest" is the one that is chosen.
The interface Sparta
is defined within a base class. The class Sparta
is defined in the containing namespace. Things defined within a base class are "closer" than things defined in the same namespace.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With