Qual é a melhor maneira de estruturar e nomear arquivos que contêm classes genéricas com o mesmo nome?


14

No meu projeto atual, me deparei com o requisito de criar classes genéricas com o mesmo nome, mas com números diferentes de parâmetros genéricos. Por exemplo:

MyClass<T1>
MyClass<T1, T2>
MyClass<T1, T2, T3>

Como eu quero tudo isso no mesmo espaço para nome, estou confuso sobre como estruturar e nomear minhas classes e arquivos?

Se seguirmos a ideia de que devemos ter classes limitadas a uma por arquivo e que esses arquivos estejam em uma estrutura de pastas que represente a hierarquia de namespace e que o nome do arquivo corresponda ao nome da classe, como eu lido com essa situação ?

O que realmente estou perguntando aqui é: como devo nomear o arquivo que contém MyClass<T1>e como devo nomear o arquivo que contém MyClass<T1, T2>? Não estou perguntando quais devem ser os nomes dos parâmetros de tipo.


Dê-nos alguns exemplos específicos que descrevem o problema com mais detalhes. Os exemplos que você forneceu são muito ... genéricos. O que você quer dizer com "como estruturar e nomear minhas classes e arquivos?"
Robert Harvey

A Microsoft faz isso por si só, acrescentando um número ao parâmetro type. Consulte os documentos da Tupla: msdn.microsoft.com/en-us/library/…
Pete

@Pete: Isso realmente só se aplica à Tuple. A Microsoft também usa a TKey, TValueconvenção. Func tem um TResultparâmetro de tipo. Embora eu concorde que você possa usar T1, T2etc. para um número variável de parâmetros de entrada que, de outra forma, não têm usos específicos como TKeye TValue.
Robert Harvey

@RobertHarvey Bem, sim, mas apenas no contexto de uma coleção real de chave / valor, como um dicionário. Para qualquer coisa que consiste em um número variável de tipos, eles acrescentam um número. Aqui está outro exemplo: msdn.microsoft.com/en-us/library/dd402872(v=vs.110).aspx
Pete

1
Bem, suas edições obsoletas alguns dos comentários. :) Por que você não pode simplesmente manter as classes no mesmo arquivo físico? Se eles são tão diferentes que você precisa mantê-los em arquivos separados, pode nos dizer o que os torna diferentes?
Pete

Respostas:


14
MyGenericClass`1.cs
MyGenericClass`2.cs
MyGenericClass`3.cs

E assim por diante, onde o número após o backtick é o número de parâmetros de tipo genérico. Esta convenção é usada pela Microsoft.

Como alternativa, você pode usar algo como

MyGenericCollectionClass[TKey, TValue].cs

que preserva não apenas o número de parâmetros de tipo genérico, mas também seus nomes específicos. É verdade que não preserva os colchetes angulares, mas não podemos ter tudo na vida que queremos, podemos?


1
O compilador gerencia internamente o nome dos tipos genéricos, adicionando um backtick e o número de parâmetros genéricos, já que o .NET não permite vários tipos com o mesmo nome com um número diferente de parâmetros genéricos, mas o C # permite. Portanto, a convenção de nomenclatura de arquivos corresponde ao que o compilador faz.
CodesInChaos

1
Eu queria provar que você estava errado, mas na verdade você está correto: github.com/dotnet/corefx/tree/master/src/… Não gosto dessa convenção.
Den

1
@ Den, parece que agora eles se arrependeram dessa convenção. Talvez isso implique algum problema? github.com/dotnet/corefx/commit/…
Sam

@ Sam Espero que não seja um problema de comunicação entre as equipes da Microsoft. Porque ninguém mais está fazendo isso. Também cabe à equipe do compilador, não à equipe da biblioteca, decidir na minha opinião.
Den

Eu não teria coragem de usar "` "em um nome de arquivo.
Cristian E.

4

No caso Tuplee Actionque Pete mencionou, a própria Microsoft usa um único arquivo - consulte Tuple.cs e Action.cs .

Eu acho que depende em parte se a funcionalidade de todas as classes é basicamente a mesma. Pessoalmente, não gosto de agrupar classes em um único arquivo, mas isso pode ser uma exceção. No código-fonte em que trabalho, adicionei uma NamedTupleclasse gerada automaticamente (usando T4) que age da mesma maneira que Tuple, mas com um nome de string como o primeiro argumento no construtor.

Para responder sua pergunta, se você não quiser usar um único arquivo, talvez use MyClass_1.cs for MyClass<T1>, MyClass_2.cs for MyClass<T1, T2>, etc.

Nenhuma opção é ideal, portanto, eu estaria inclinado a sugerir o argumento "Microsoft faça dessa maneira, então ...".


2
Tuplee Actionsão todos delegados; eles não possuem código de implementação, portanto, colocar todas as variações em arquivos separados seria meio inútil. Apenas prova que toda regra tem uma exceção.
Robert Harvey

Sim, em geral, colocar vários delegados públicos no mesmo arquivo é considerado bom (desde que relacionados).
Stephen

1
@RobertHarvey, Tuplenão é um delegado, mas cada implementação é curta de qualquer maneira.
Arturo Torres Sánchez

@ ArturoTorresSánchez: Certo, eu estava pensando Func.
Robert Harvey

0

Você já se perguntou se as aulas realmente têm a mesma intenção? Se uma classe for mais genérica que a outra, será uma GenericClass , MoreGenericClass e MostGenericClass . Imagine que cada parâmetro de tipo de uma classe adicione uma nova dimensão à classe, portanto, pode ajudar perguntar qual é a dimensão.

Vamos pegar este exemplo:

  • Container<Thing>
  • MetricContainer<Thing, Metric>
  • MetricTransportableContainer<Thing, Metric, Transport>

Estou ciente de que não é o melhor exemplo, mas é muito expressivo para mostrar três dimensões:

  • Dimensão interna, o que pode carregar
  • métrica Dimensão, com a qual a métrica pode ser carregada, apenas pela contagem de itens ou por medida quadrada ou por capacidade cúbica ou por peso
  • Dimensão externa, onde pode ser carregado.

Então você pode modelar o transporte de carros:

Container<Cars>
MetricContainer<Cars, CountMetric>
MetricTransportableContainer<Cars, CountMetric, Ship>

Transporte de fluidos:

Container<Fluid>
MetricContainer<Fluid, Volume>
MetricTransportableContainer<Fluid, Volume, Shelf>

Transporte de energia:

Container<Energy>
MetricContainer<Energy, ElectricPower>
MetricTransportableContainer<Energy, ElectricPower, Box>

Transporte de açúcar, cereais:

Container<CrumblyMaterial>
MetricContainer<CrumblyMaterial, Weight>
MetricTransportableContainer<CrumblyMaterial, Weight, Silo>

Oh, que surpresa: a List<T>tem uma dimensão que representa o que a lista pode conter; e este é um Map<T, S>com duas dimensões que representam o que o mapa pode conter e as teclas de acesso.


1
Eu não acho que você entendeu a pergunta. Veja o último parágrafo da pergunta.
Robert Harvey

1
@RobertHarvey Por favor, leia a pergunta com atenção: o nome da classe deve ser equivalente ao nome do arquivo. É intercambiável. O problema está na análise incorreta da classe e na nomeação incorreta das classes genéricas em geral. Para resumir minha resposta: "Nomeie o que é e não o que parece ser".
shylynx


1
@RobertHarvey Leia minha resposta: Coloque uma classe em um arquivo!
shylynx

1
Eu acho que você está perdendo o ponto. A pergunta é: Como faço para colocar Tuple<T1>, Tuple<T1, T2>e Tuple<T1, T2, T3>em arquivos CS separadas de uma forma padrão, sem conflitos de nome?
Robert Harvey
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.