
Hoje à noite, gelas iniciou uma conversa sobre como os gerenciadores de pacotes trabalham em diferentes plataformas. Durante a conversa, discutimos a situação em que você precisa conectar duas bibliotecas a um projeto no .NET Core que contém classes com o mesmo nome no mesmo espaço para nome. Como estou usando bastante o .NET Core, queria verificar como esse problema pode ser resolvido. O que veio disso é descrito mais detalhadamente
Isenção de responsabilidade . Essas situações ocorrem com frequência? Por mais de 10 anos trabalhando com o .NET, nunca tive que lidar com uma situação semelhante em um projeto real. Mas o experimento foi interessante.
Apenas para esclarecer, vou esclarecer que conduzirei o experimento usando:
- macOS 10.13,
- .NET Core SDK 2.1.302
- Rider 2018.2
Então, simularemos uma situação quando tivermos duas bibliotecas que possuem as classes necessárias e que devemos usar em nosso projeto. Ao mesmo tempo, não temos acesso ao código fonte, mas não podemos descompilar os assemblies para alterar o namespace neles e, em seguida, também não podemos compilar novamente.
Preparação da experiência
E assim, para começar, prepare uma coruja e dois globos. Como coruja, teremos um projeto direcionado ao netcoreapp2.1. Criaremos dois projetos como globos, um dos quais também será direcionado para netcoreapp2.1 e o segundo para netstandard2.0

Em cada projeto, colocamos a classe Globe, que estará em namespaces idênticos, mas eles terão implementações diferentes:
Primeiro arquivo:
using System; namespace Space { public class Globe { public string GetColor() => "Green"; } }
Segundo arquivo:
using System; namespace Space { public class Globe { public string GetColor() => "Blue"; } }
Tentativa número um
Como, de acordo com as condições do problema, devemos trabalhar com assemblies externos, e não projetos, adicionaremos links ao projeto adequadamente, como se fossem realmente apenas bibliotecas. Para fazer isso, primeiro compile todos os projetos para que tenhamos o Globe1.dll e o Globe2.dll necessários. Em seguida, adicione links a eles no projeto da seguinte maneira:

Agora tente criar uma variável de classe Globe:

Como você pode ver, já neste estágio o IDE nos alerta que há um problema em entender de onde a classe Globe de que precisamos deve ser tirada.
A princípio, parece que a situação é bastante típica e já deve haver uma resposta pronta, moldada em granito, para Stack Overflow. Como se viu, ainda não foi proposta nenhuma solução para esse problema para o .NET Core. Ou meu Google me decepcionou. Mas consegui encontrar algo útil no Stack Overflow.A única publicação sensata que consegui pesquisar no Google foi em 2006 e descrevi uma situação semelhante para a versão clássica do .NET. Nesse caso, um problema muito semelhante é discutido no repositório do projeto NuGet .
Até o momento, não há muitas informações úteis, mas ainda existem:
- Na versão clássica do .NET, um mecanismo de alias foi implementado
- De acordo com a especificação, o C # suporta o uso de aliases no código
Resta entender como fazer isso no .NET Core.
Infelizmente, a versão atual da documentação fala modestamente sobre as possibilidades de conectar pacotes / taxas externas. E a descrição do arquivo csproj também não esclarece a possibilidade de criar aliases. No entanto, por tentativa e erro, pude descobrir que ainda há suporte para aliases para assemblies no .NET Core. E eles são feitos da seguinte maneira:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp2.1</TargetFramework> </PropertyGroup> <ItemGroup> <Reference Include="Globe1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"> <HintPath>..\Globe1\bin\Debug\netcoreapp2.1\Globe1.dll</HintPath> <Aliases>Lib1</Aliases> </Reference> <Reference Include="Globe2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"> <HintPath>..\Globe2\bin\Debug\netstandard2.0\Globe2.dll</HintPath> <Aliases>Lib2</Aliases> </Reference> </ItemGroup> </Project>
Agora resta aprender a usar esses aliases. A palavra-chave externa mencionada anteriormente nos ajudará com isso:
O seguinte está escrito na documentação sobre o assunto:
Em alguns casos, pode ser necessário fazer referência a duas versões de montagens com os mesmos nomes de tipo totalmente qualificados. Por exemplo, você precisa usar duas ou mais versões de um assembly em um aplicativo. Usando um alias de montagem externo, é possível incluir espaços para nome para cada montagem em um wrapper dentro dos espaços para nome no nível raiz nomeados por esse alias, o que permite usá-los em um único arquivo.
...
Cada declaração de um alias externo introduz um espaço para nome adicional no nível raiz que corresponde ao espaço para nome global (mas não está dentro dele). Assim, as referências aos tipos de cada montagem sem ambiguidade podem ser criadas usando seu nome completo, cuja raiz é o alias do espaço para nome correspondente.
A verdade aqui é não esquecer que extern também é usado em C # para declarar um método com uma implementação externa a partir de código não gerenciado. Nesse caso, extern é geralmente usado com o atributo DllImport. Você pode ler mais sobre isso na seção correspondente da documentação .
Então, vamos tentar usar nossos aliases:
extern alias Lib1; extern alias Lib2; using System; namespace Owl { ... public class SuperOwl { private Lib1::Space.Globe _firstGlobe; private Lib2::Space.Globe _secondGlobe; public void IntegrateGlobe(Lib1::Space.Globe globe) => _firstGlobe = globe; public void IntegrateGlobe(Lib2::Space.Globe globe) => _secondGlobe = globe; ... } }
Este código já funciona. E funciona corretamente. Mas ainda quero torná-lo um pouco mais elegante. Isso pode ser feito de uma maneira muito simples:
extern alias Lib1; extern alias Lib2; using System; using SpaceOne=Lib1::Space; using SpaceTwo=Lib2::Space;
Agora você pode usar a sintaxe usual e óbvia:
var globe1 = new SpaceOne.Globe() var globe2 = new SpaceTwo.Globe()
Teste
Vamos testar nossa coruja:

Como você pode ver, o código funcionou bem e sem erros. A integração de corujas e globos foi concluída com sucesso!
→ Código de exemplo está disponível no GitHub