Namespace e classe com o mesmo nome?


95

Estou organizando um projeto de biblioteca e tenho uma classe de gerenciador central chamada Scenegraphe um monte de outras classes que vivem no namespace Scenegraph.

O que eu realmente gostaria é que o Scenegraph MyLib.Scenegraphe as outras classes o sejam MyLib.Scenegraph.*, mas parece que a única maneira de fazer isso seria tornar todas as outras classes internas Scenegraphno arquivo Scenegraph.cs e isso é muito pesado .

Em vez disso, organizei-o como Mylib.Scenegraph.Scenegraphe MyLib.Scenegraph.*, o que meio que funciona, mas acho que o Visual Studio fica confuso em algumas condições se estou me referindo à classe ou ao namespace.

Existe uma boa maneira de organizar este pacote de forma que seja conveniente para os usuários, sem agrupar todo o meu código em uma bagunça impossível de manter?

Respostas:


112

Eu não recomendo que você nomeie uma classe como seu namespace, veja isto .

O Framework Design Guidelines diz na seção 3.4 “não use o mesmo nome para um namespace e um tipo nesse namespace”. Isso é:

namespace MyContainers.List 
{ 
    public class List {  } 
}

Por que isso é maldade? Oh, deixe-me contar as maneiras.

Você pode se colocar em situações em que pensa que está se referindo a uma coisa, mas na verdade está se referindo a outra. Suponha que você termine nesta situação infeliz: você está escrevendo Blah.DLL e importando Foo.DLL e Bar.DLL, que, infelizmente, ambos têm um tipo chamado 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; } 
}

O compilador fornece um erro. “Foo” é ambíguo entre Foo.Foo e Bar.Foo. Vadio. Acho que vou consertar isso qualificando totalmente o nome:

   class C { Foo.Foo foo; } 

Isso agora dá o erro de ambigüidade “ Foo em Foo.Foo é ambíguo entre Foo.Foo e Bar.Foo ”. Ainda não sabemos a que o primeiro Foo se refere, e até que possamos descobrir isso, nem nos importamos em tentar descobrir a que o segundo se refere.


6
É um ponto interessante. Eu ainda estou pensando sobre isso. Obrigado. Tenho que ser argumentos honestos que começam com "O guia de estilo diz" não me impressionam. Já vi muitas porcarias injustificadas nos guias de estilo. Mas você fez um bom argumento prático acima. Vale a pena pensar nisso, de qualquer maneira.
user430788

5
A resposta diz "o que não fazer". Enquanto alguns usuários da pilha procuram "o que fazer". Alguém recomendaria a resposta Ant_222?
fantastory de

3
Se você estiver realmente travado, ainda poderá criar um alias de tipo fora do seu namespace. Aliases externos são necessários apenas quando você tem dois identificadores completos completamente idênticos (namespace + nome da classe).
Geoffrey

3
Todos os itens acima são por-tchau e opinião. O fato é que você não deve fazer isso porque o compilador C # irá entendê-lo mal , apesar de ser informado de forma bastante clara o que está acontecendo. Por exemplo, using Foo.Bar;mais tarde Bar bestá claramente se referindo a Baruma classe (ou enum) dentro do namespace Foo.Bar. A verdadeira razão para não fazer isso é puramente que o compilador C # não consegue entendê-lo corretamente, o que é terrivelmente surpreendente e lamentável. Qualquer outra coisa é um conselho de estilo confuso.
TJ Crowder

2
Eu não entendo. Por que Foo.Foo é ambíguo? Você diz diretamente ao compilador que deseja usar a classe Foo do namespace Foo neste caso específico. Não?
GuardianX

14

Dar o mesmo nome ao namespace e à classe pode confundir o compilador como outros disseram.

Como nomear então?

Se o namespace tiver várias classes, encontre um nome que defina todas essas classes.

Se o namespace tiver apenas uma classe (e, portanto, a tentação de dar a ela o mesmo nome), nomeie o namespace ClassName NS . É assim que a Microsoft nomeia seus namespaces, pelo menos.


4
Você tem um exemplo de namespace da Microsoft?
sunefred em

Eu tenho que pesquisar e voltar para você.
GoTo

@sunefred Eu procurei, mas não consegui encontrar. Mas eu definitivamente me lembro de ter visto isso na documentação. Acho que não há muitos casos em que você deseja ter uma única classe em um namespace.
GoTo

9

Eu sugeriria que você siga o conselho que comecei microsoft.public.dotnet.languages.csharpa usar MyLib.ScenegraphUtil.Scenegraphe MyLib.ScenegraphUtil.*.



4

Apenas adicionando meus 2 centavos:

Tive a seguinte aula:

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

O cliente foi escrito assim:

using Foo;

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

Perdoando o erro GetFoo não retornar a saída em vez de usar o parâmetro out, o compilador não pôde resolver o tipo de dados Foo.Bar []. Ele estava retornando o erro: não foi possível encontrar o tipo ou namespace Foo.Bar.

Parece que ao tentar compilar, ele resolveu Foo como a classe e não encontrou uma classe Bar embutida na classe Foo. Ele também não conseguiu encontrar um namespace chamado Foo.Bar. Ele falhou ao procurar por uma classe Bar no namespace Foo. Os pontos em um espaço de nome NÃO são sintáticos. A string inteira é um token, não as palavras delimitadas por pontos.

Este comportamento foi exibido pelo VS 2015 executando .Net 4.6


4

Mesmo que eu concorde com outras respostas no sentido de que você não deve nomear sua classe da mesma forma que seu namespace há momentos em que você não pode cumprir esses requisitos.

No meu caso, por exemplo, não fui eu quem tomou essa decisão, portanto, precisava encontrar uma maneira de fazê-la funcionar.

Portanto, para aqueles que não podem alterar o nome do namespace nem o nome da classe, aqui está uma maneira de fazer seu código funcionar.

// 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
}

Basicamente, criei "aliases" de namespace e isso me permitiu qualificar totalmente a classe e a "confusão" do Visual Studio foi embora.

NOTA: Você deve evitar esse conflito de nomes se estiver sob seu controle. Você só deve usar a técnica mencionada quando não estiver no controle das classes e namespaces em questão.


2
Votei porque era uma solução interessante para um mundo imperfeito.
user430788

2

Postagem antiga, mas aí vou eu com outra ideia que pode ajudar alguém:

"... mas parece que a única maneira de fazer isso seria tornar todas as outras classes classes internas do Scenegraph no arquivo Scenegraph.cs e isso é muito pesado."

Esta é realmente a melhor implementação para vários cenários. Mas, eu concordo que ter todo esse código no mesmo arquivo .cs é irritante (para dizer o mínimo).

Você poderia resolvê-lo tornando a classe base uma "classe parcial" e, em seguida, continuar criando as classes internas em seus próprios arquivos (apenas lembre-se de que eles terão que declarar o complemento da classe base e então continuar com a classe interna específica para esse arquivo).

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
        }
    }
}

Eu realmente acho que isso é o mais perto que você pode chegar de ter uma implementação limpa de classes internas, sem ter que desordenar tudo dentro de um arquivo enorme e confuso.


2

Como outros já disseram, é uma boa prática evitar nomear uma classe da mesma forma que seu namespace.

Aqui estão algumas sugestões de nomenclatura adicionais de uma resposta de svick a uma pergunta relacionada "Same class and namespace name" no Software Engineering Stack Exchange:

Você está certo ao dizer que não deve nomear o namespace igual ao tipo que ele contém. Acho que existem várias abordagens que você pode usar:

  • Pluralize: Model.DataSources.DataSource

Isso funciona especialmente bem se o objetivo principal do namespace for conter tipos que herdam do mesmo tipo base ou implementam a mesma interface.

  • Encurtar: Model.QueryStorage

Se um namespace contém apenas um pequeno número de tipos, talvez você nem precise desse namespace.

  • Faça enterprisey: Model.ProjectSystem.Project

Isso pode funcionar especialmente para recursos que são parte importante do seu produto, portanto, eles merecem seu próprio nome.

(Note-se que os usos resposta acima Model.DataSource.DataSource, Model.QueryStorage.QueryStorage.eModel.Project.Project como exemplos, em vez deMyLib.Scenegraph.Scenegraph .)

(Também achei úteis as outras sugestões de nomes nas outras respostas aqui).


1

Acontece quando é a classe principal do namespace. Portanto, é uma motivação colocar o namespace em uma biblioteca, o problema desaparece se você adicionar 'Lib' ao nome do namespace ...

namespace SocketLib
{
    class Socket
    {
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.