¿Espacio de nombres y clase con el mismo nombre?


95

Estoy organizando un proyecto de biblioteca y tengo una clase de administrador central llamada Scenegraphy un montón de otras clases que viven en el espacio de nombres de Scenegraph.

Lo que realmente me gustaría es que sea el scenegraph MyLib.Scenegraphy las otras clases MyLib.Scenegraph.*, pero parece que la única forma de hacerlo sería hacer que todas las demás clases sean clases internas Scenegraphen el archivo Scenegraph.cs y eso es demasiado difícil de manejar .

En cambio, lo he organizado como Mylib.Scenegraph.Scenegraphy MyLib.Scenegraph.*, lo que funciona, pero encuentro que Visual Studio se confunde bajo algunas condiciones en cuanto a si me refiero a la clase o al espacio de nombres.

¿Existe una buena manera de organizar este paquete para que sea conveniente para los usuarios sin tener que juntar todo mi código en un lío inmaterial?

Respuestas:


111

No te recomiendo que nombre una clase como su espacio de nombres, mira esto .

Las Pautas de diseño del marco dicen en la sección 3.4 “no use el mismo nombre para un espacio de nombres y un tipo en ese espacio de nombres”. Es decir:

namespace MyContainers.List 
{ 
    public class List {  } 
}

¿Por qué esta maldad? Oh, dejame contar las maneras.

Puede meterse en situaciones en las que cree que se refiere a una cosa, pero en realidad se refiere a otra. Suponga que termina en esta desafortunada situación: está escribiendo Blah.DLL e importando Foo.DLL y Bar.DLL, que, desafortunadamente, ambos tienen un tipo llamado Foo:

// Foo.DLL: 
namespace Foo { public class Foo { } }

// Bar.DLL: 
namespace Bar { public class Foo { } }

// Blah.DLL: 
namespace Blah  
{   
using Foo;   
using Bar;   
class C { Foo foo; } 
}

El compilador da un error. “Foo” es ambiguo entre Foo.Foo y Bar.Foo. Gorrón. Supongo que lo arreglaré calificando completamente el nombre:

   class C { Foo.Foo foo; } 

Esto ahora da el error de ambigüedad " Foo in Foo.Foo es ambiguo entre Foo.Foo y Bar.Foo ". Todavía no sabemos a qué se refiere el primer Foo, y hasta que podamos averiguarlo, ni siquiera nos molestamos en tratar de averiguar a qué se refiere el segundo.


6
Es un punto interesante. Todavía estoy cogiéndolo. Gracias. Tengo que ser honesto con los argumentos que comienzan con "La guía de estilo dice" no me impresionen. He visto una gran cantidad de basura injustificada en las guías de estilo. Pero hace un buen argumento práctico arriba. Vale la pena pensar en ello, de todos modos.
user430788

5
La respuesta dice "qué no hacer". Mientras que algunos usuarios de la pila buscan "qué hacer". ¿Alguien recomendaría la respuesta de Ant_222?
fantastory

3
Si está realmente atascado, aún puede crear un alias de tipo fuera de su espacio de nombres. Los alias externos solo son necesarios cuando tiene dos identificadores completos completamente idénticos (espacio de nombres + nombre de clase).
Geoffrey

4
Todo lo anterior es por adiós y opinión. El hecho es que no debería hacerlo porque el compilador de C # lo malinterpretará , a pesar de que le digan claramente lo que está pasando. Por ejemplo, using Foo.Bar;later Bar bse refiere claramente a Baruna clase (o enumeración) dentro del espacio de nombres Foo.Bar. La verdadera razón para no hacer eso es simplemente que el compilador de C # no lo entiende correctamente, lo cual es tremendamente sorprendente y desafortunado. Cualquier otra cosa es un consejo de estilo lanoso.
TJ Crowder

2
No lo entiendo. ¿Por qué Foo.Foo es ambiguo? Le dice directamente al compilador que quiere usar la clase Foo del espacio de nombres Foo en este caso específico. ¿No?
GuardianX

14

Dar el mismo nombre al espacio de nombres y la clase puede confundir al compilador como han dicho otros.

¿Cómo nombrarlo entonces?

Si el espacio de nombres tiene varias clases, busque un nombre que defina todas esas clases.

Si el espacio de nombres tiene solo una clase (y por lo tanto la tentación de darle el mismo nombre), nombre el espacio de nombres ClassName NS . Así es como Microsoft nombra al menos sus espacios de nombres.


4
¿Tiene un ejemplo de un espacio de nombres de este tipo de Microsoft?
sunefred

Tengo que buscarlo y volver contigo.
Vaya al

@sunefred Lo busqué, pero no pude encontrarlo. Pero definitivamente recuerdo haberlo visto en la documentación. Supongo que no hay muchos casos en los que desee tener una sola clase en un espacio de nombres.
Vaya al

9

Le sugiero que siga los consejos que seguí microsoft.public.dotnet.languages.csharppara usar MyLib.ScenegraphUtil.Scenegraphy MyLib.ScenegraphUtil.*.



4

Solo agregando mis 2 centavos:

Tuve la siguiente clase:

namespace Foo {
    public struct Bar {
    }
    public class Foo {
        //no method or member named "Bar"
    }
}

El cliente fue escrito así:

using Foo;

public class Blah {
    public void GetFoo( out Foo.Bar[] barArray ) {
    }
}

Perdonando el error GetFoo de no devolver la salida en lugar de usar el parámetro out, el compilador no pudo resolver el tipo de datos Foo.Bar []. Devolvía el error: no se pudo encontrar el tipo o el espacio de nombres Foo.Bar.

Parece que cuando intenta compilar resolvió Foo como la clase y no encontró una clase Bar incrustada en la clase Foo. Tampoco pudo encontrar un espacio de nombres llamado Foo.Bar. No pudo buscar una barra de clases en el espacio de nombres Foo. Los puntos en un espacio de nombres NO son sintácticos. Toda la cadena es una ficha, no las palabras delimitadas por puntos.

Este comportamiento fue exhibido por VS 2015 ejecutando .Net 4.6


4

Aunque estoy de acuerdo con otras respuestas en que no debe nombrar su clase de la misma manera que su espacio de nombres, hay ocasiones en las que no puede cumplir con dichos requisitos.

En mi caso, por ejemplo, yo no era la persona que tomaba esa decisión, por lo que necesitaba encontrar una manera de hacerlo funcionar.

Entonces, para aquellos que no pueden cambiar el nombre del espacio de nombres ni el nombre de la clase, aquí hay una forma en la que puede hacer que su código funcione.

// Foo.DLL: 
namespace Foo { public class Foo { } }

// Bar.DLL: 
namespace Bar { public class Foo { } }

// Blah.DLL: 
namespace Blah
{
    using FooNSAlias = Foo;//alias
    using BarNSAlias = Bar;//alias
    class C { FooNSAlias.Foo foo; }//use alias to fully qualify class name
}

Básicamente, creé "alias" de espacio de nombres y eso me permitió calificar completamente la clase y la "confusión" de Visual Studio desapareció.

NOTA: Debe evitar este conflicto de nombres si está bajo su control. Solo debe usar la técnica mencionada cuando no tenga el control de las clases y los espacios de nombres en cuestión.


2
Lo voté a favor porque era una solución interesante para un mundo imperfecto.
user430788

2

Publicación antigua, pero aquí voy con otra idea que puede ayudar a alguien:

"... pero parece que la única forma de hacerlo sería hacer que todas las demás clases sean clases internas de Scenegraph en el archivo Scenegraph.cs y eso es demasiado difícil de manejar".

Esta es realmente la mejor implementación para un montón de escenarios. Pero, estoy de acuerdo en que tener todo ese código en el mismo archivo .cs es molesto (por decir lo menos).

Puede resolverlo haciendo que la clase base sea una "clase parcial" y luego, continuar creando las clases internas en sus propios archivos (solo recuerde que tendrán que declarar el complemento de la clase base y luego continuar con la clase interna específica para ese archivo).

Algo como...

Scenegraph.cs:

namespace MyLib
{
    public partial class Scenegraph
    {
        //Scenegraph specific implementations
    }
}

DependentClass.cs:

namespace MyLib
{
    public partial class Scenegraph
    {
        public class DependentClass
        {
            //DependentClass specific implementations
        }
    }
}

Creo que esto es lo más cerca que puede estar de tener la implementación limpia de clases internas sin tener que desordenar todo dentro de un archivo enorme y desordenado.


2

Como han dicho otros, es una buena práctica evitar nombrar una clase como su espacio de nombres.

Aquí hay algunas sugerencias de nomenclatura adicionales de una respuesta de svick a una pregunta relacionada "Misma clase y nombre de espacio de nombres" en el Intercambio de pila de ingeniería de software:

Tiene razón en que no debe nombrar el espacio de nombres de la misma manera que el tipo que contiene. Creo que hay varios enfoques que puedes usar:

  • Pluralizar: Model.DataSources.DataSource

Esto funciona especialmente bien si el propósito principal del espacio de nombres es contener tipos que hereden del mismo tipo base o implementar la misma interfaz.

  • Acortar: Model.QueryStorage

Si un espacio de nombres contiene solo una pequeña cantidad de tipos, tal vez no necesite ese espacio de nombres en absoluto.

  • Hacer empresa: Model.ProjectSystem.Project

Esto puede funcionar especialmente para características que son parte importante de su producto, por lo que merecen su propio nombre.

(Tenga en cuenta que los usos anteriores de respuesta Model.DataSource.DataSource, Model.QueryStorage.QueryStorage.y Model.Project.Projectcomo ejemplos en lugar de MyLib.Scenegraph.Scenegraph.)

(También encontré útiles las otras sugerencias de nombres en las otras respuestas aquí).


1

Sucede cuando es la clase principal del espacio de nombres. Así que es una motivación poner el espacio de nombres en una biblioteca, luego el problema desaparece si agrega 'Lib' al nombre del espacio de nombres ...

namespace SocketLib
{
    class Socket
    {
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.