Como resolver colisão de nomes de tipos [Dica Rápida .Net] – Robson Castilho
Há alguns dias, mexendo em um código legado, tive que incluir uma nova feature e, para isso, precisei adicionar uma referência a outro assembly, vamos chamar de "A", no assembly (csproj) em que eu estava trabalhando.
Feito isso, o código deixou de compilar! Motivo: o código fazia uso de uma classe que possuía exatamente o mesmo nome de outra classe contida no assembly "A". Sim, nome e o namespace completo iguaizinhos.
Como alterar o nome de uma delas era simplesmente inviável naquele momento, procurei alguma solução que pudesse desambiguar os nomes e descobri algo extremamente simples neste artigo aqui, de 2006!
(Como o artigo é muito antigo e o blog parece estar abandonado desde aquela época, vou descrever aqui a solução, caso aquele blog saia do ar.)
1. Crie uma nova Solution e adicione dois projetos novos, ambos do tipo Class Library, chamados FooVersion1 e FooVersion2.
2. No projeto FooVersion1, adicione a classe abaixo:
3. No projeto FooVersion2, adicione a classe abaixo (veja que tanto o namespace quanto o nome dela são iguais à da classe anterior):
public void Goo() => Console.WriteLine("Goo");
4. Agora, para reproduzir o erro, adicione mais um projeto na Solution, dessa vez do tipo Console App, e chame-o de Consumer.
5. Adicione no Consumer, referências para os dois outros projetos, FooVersion1 e FooVersion2 (right-click em "References" ou "Dependencies" -> "Add Reference…").
6. Ainda no Consumer, no método Main da classe Program (gerada automaticamente por ter criado um Console App), adicione o seguinte código e compile a aplicação:
var foo = new Acme.Foo();
7. Com isso, veremos o erro de compilação mais ou menos como abaixo:
"The type 'Acme.Foo' exists in both 'FooVersion1…' and 'FooVersion2…'"
8. Para compilar, é preciso resolver a ambiguidade, o que é feito usando aliases para os assemblies referenciados. Vamos fazer isso para o FooVersion1. No projeto Consumer, ache a dependência FooVersion1 e entre em "Properties":
Na janela que abrir, altere a propriedade "Aliases" para "LibFooVersion1":
obs.: exemplo usando projetos .Net Core com VS 2017 (as opções são ligeiramente diferentes em um projeto .Net full).
9. Basta compilar novamente o Consumer e você verá que o erro foi embora, porque agora o compilador entende que a classe Foo usada é a classe vinda de FooVersion2, que é a dependência onde não foi definido nenhum alias específico.
10. "E se eu quiser usar a outra classe?" Também é muito simples: basta fazer uso do alias definido no item 8. Primeiro, no topo do arquivo Program.cs do Consumer, coloque a seguinte diretiva (deve ser a primeira instrução dentro do arquivo):
extern alias LibFooVersion1;
11. E agora, altere o método Main para:
var f1 = new LibFooVersion1::Acme.Foo();
var f2 = new Acme.Foo();
12. Pronto! Agora é possível usar ambos os tipos, sem qualquer conflito. O próprio IntelliSense indicará os métodos corretos, de acordo com o tipo criado.
Obs.: você também poderia ter colocado um alias para o projeto FooVersion2, porém, recomendo deixar sem alias o tipo que aparece mais vezes no código, deixando-o mais limpo e sem necessidade de repetir em vários arquivos o uso da diretiva "extern alias".
Use esta solução com parcimônia. Evite ao máximo a colisão de nomes, dando nomes bem explícitos e objetivos às suas classes e namespaces. Assim, além de evitar o problema descrito aqui, tanto para você quanto para qualquer outro consumidor da sua DLL, você também deixará o código mais fácil de ser entendido.