que namespace multiple method inherited inherit example c# inheritance types namespaces

c# - namespace - Este es Sparta, ¿o sí?



namespace c# que es (3)

Pero, ¿por qué Sparta en MakeItReturnFalse() refiere a {namespace}.Place.Sparta lugar de {namespace}.Sparta ?

Básicamente, porque eso es lo que dicen las reglas de búsqueda de nombres. En la especificación C # 5, las reglas de nomenclatura relevantes se encuentran en la sección 3.8 ("Espacio de nombres y nombres de tipo").

Los primeros dos puntos, truncados y anotados, se leen:

  • Si el nombre del espacio de nombres o tipos es de la forma I o de la forma I<A1, ..., AK> [entonces K = 0 en nuestro caso] :
    • Si K es cero y el nombre del espacio de nombres o tipos aparece dentro de una declaración de método genérico [no, no hay métodos genéricos]
    • De lo contrario, si el espacio de nombre o nombre de tipo aparece dentro de una declaración de tipo, entonces para cada tipo de instancia T (§10.3.1), comenzando con el tipo de instancia de esa declaración de tipo y continuando con el tipo de instancia de cada clase adjunta o declaración de estructura (si existe):
      • Si K es cero y la declaración de T incluye un parámetro de tipo con el nombre I , entonces el espacio de nombres o nombre de tipo se refiere a ese parámetro de tipo. [No]
      • De lo contrario, si el nombre de espacio de nombres o tipos aparece dentro del cuerpo de la declaración de tipo, y T o cualquiera de sus tipos base contienen un tipo accesible anidado que tiene parámetros de tipo de nombre I y K , entonces el nombre de espacio de nombre o tipo se refiere a ese tipo construido con los argumentos de tipo dados. [¡Bingo!]
  • Si los pasos anteriores no tuvieron éxito, entonces, para cada espacio de nombres N , comenzando con el espacio de nombres en el que se produce el espacio de nombres o nombres de tipos, continuando con cada espacio de nombres adjunto (si corresponde) y terminando con el espacio de nombres global, los siguientes pasos son evaluado hasta que se localice una entidad:
    • Si K es cero e I es el nombre de un espacio de nombres en N , entonces ... [Sí, eso tendría éxito]

Entonces, ese último punto es lo que recoge la clase Sparta si el primer punto no encuentra nada ... pero cuando la clase base Place define una interfaz Sparta , se encuentra antes de considerar la clase Sparta .

Tenga en cuenta que si hace que el tipo anidado Place.Sparta una clase en lugar de una interfaz, aún se compila y devuelve false , pero el compilador emite una advertencia porque sabe que una instancia de Sparta nunca será una instancia de la clase Place.Sparta . Del mismo modo, si mantiene Place.Sparta una interfaz pero sealed clase Sparta , recibirá una advertencia porque ninguna instancia de Sparta podría implementar la interfaz.

La siguiente es una pregunta de entrevista. Se me ocurrió una solución, pero no estoy seguro de por qué funciona.

Pregunta:

Sin modificar la clase Sparta , escriba un código que haga que MakeItReturnFalse devuelva false .

public class Sparta : Place { public bool MakeItReturnFalse() { return this is Sparta; } }

Mi solución: (SPOILER)

public class Place
{
public interface Sparta { }
}

Pero, ¿por qué Sparta en MakeItReturnFalse() refiere a {namespace}.Place.Sparta lugar de {namespace}.Sparta ?


Al resolver un nombre a su valor, la "cercanía" de la definición se utiliza para resolver ambigüedades. Cualquier definición que sea "más cercana" es la que se elige.

La interfaz Sparta se define dentro de una clase base. La clase Sparta se define en el espacio de nombres que contiene. Las cosas definidas dentro de una clase base están "más cerca" que las cosas definidas en el mismo espacio de nombres.


Hermosa pregunta! Me gustaría agregar una explicación un poco más larga para aquellos que no hacen C # a diario ... porque la pregunta es un buen recordatorio de los problemas de resolución de nombres en general.

Tome el código original, ligeramente modificado de las siguientes maneras:

  • Imprimamos los nombres de los tipos en lugar de compararlos como en la expresión original (es decir, return this is Sparta ).
  • Definamos la interfaz Athena en la superclase Place para ilustrar la resolución del nombre de la interfaz.
  • Imprimamos también el nombre del tipo de this ya que está vinculado en la clase Sparta , solo para aclararlo todo.

El código se ve así:

public class Place { public interface Athena { } } public class Sparta : Place { public void printTypeOfThis() { Console.WriteLine (this.GetType().Name); } public void printTypeOfSparta() { Console.WriteLine (typeof(Sparta)); } public void printTypeOfAthena() { Console.WriteLine (typeof(Athena)); } }

Ahora creamos un objeto Sparta y llamamos a los tres métodos.

public static void Main(string[] args) { Sparta s = new Sparta(); s.printTypeOfThis(); s.printTypeOfSparta(); s.printTypeOfAthena(); } }

El resultado que obtenemos es:

Sparta Athena Place+Athena

Sin embargo, si modificamos la clase Place y definimos la interfaz Sparta:

public class Place { public interface Athena { } public interface Sparta { } }

entonces es esta Sparta , la interfaz, la que estará disponible primero para el mecanismo de búsqueda de nombres y la salida de nuestro código cambiará a:

Sparta Place+Sparta Place+Athena

Por lo tanto, hemos estropeado efectivamente la comparación de tipos en la definición de la función MakeItReturnFalse simplemente definiendo la interfaz Sparta en la superclase, que se encuentra primero por la resolución del nombre.

Pero, ¿por qué C # eligió priorizar las interfaces definidas en la superclase en la resolución de nombres? @JonSkeet lo sabe! Y si lee su respuesta, obtendrá los detalles del protocolo de resolución de nombres en C #.