📜 ⬆️ ⬇️

The problem of the owl and the globe: connecting two assemblies with identical namespaces and class names


Tonight, with gelas we started talking about how package managers work on different platforms. During the conversation, we came to discuss the situation when you need to connect two libraries to a project on .NET Core that contain classes with the same name in the same namespace. Since I do the .NET Core quite tightly, I wanted to check how this problem could be solved. What came of it is described further


Disclaimer Do such situations often occur? For more than 10 years of working with .NET, I have never had to face such a situation in a real project. But the experiment was interesting.


Just in case, I will clarify that I will conduct the experiment using:



So, let's simulate the situation when we got two libraries in which we have the classes we need, which we should use in our project. At the same time, we do not have access to the source code, and we cannot decompile assemblies in order to change the namespaces in them, and then we cannot compile them back.


Preparing the experiment


And so, for the beginning we will prepare one owl and two globes. As an owl, we will have a project with a target on netcoreapp2.1. As globes we will create two projects, one of which will also be with the target for netcoreapp2.1, and the second for netstandard2.0



In each project we put in the class Globe, which will be located in identical namespaces, but they will have different implementation:


First file:


using System; namespace Space { public class Globe { public string GetColor() => "Green"; } } 

Second file:


 using System; namespace Space { public class Globe { public string GetColor() => "Blue"; } } 

Attempt number one


Since, according to the conditions of the problem, we have to work with external assemblies, rather than projects, we will add links to the project accordingly as if they really are just libraries. To do this, we first compile all the projects so that we have the Globe1.dll and Globe2.dll we need. Then add links to the project in the following form:



Now let's try to create a variable of the class Globe:



As you can see, already at this stage, the IDE warns us that there is a problem with understanding where the required Globe class should come from.


At first it seems that the situation is quite typical and it should already be ready, cast in granite, the answer to the Stack Overflow. As it turned out, for the .NET Core solution of this problem has not yet been proposed. Either my Google let me down. But it was possible to find something useful on Stack Overflow. The only sensible publication that we managed to google was in 2006 and described a similar situation for the classic version of .NET. At the same time, a very similar problem is discussed in the repository of the NuGet project .


There is not very much useful information, but it is still there:



It remains to figure out how to do this in .NET Core.


Unfortunately, the current version of the documentation rather modestly describes the possibilities of connecting external packages / fees. And the description of the csproj file also in no way sheds light on the possibility of creating pseudonyms. But nevertheless, through trial and error, I managed to find out that aliases for assemblies in .NET Core are still supported. And they are made in the following way:


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

Now it remains to learn how to use these pseudonyms. The previously mentioned extern keyword will help us with this:


In the documentation about him write the following:


In some cases, it may be necessary to link to two versions of assemblies with the same full type names. For example, you need to use two or more versions of an assembly in the same application. Using an external assembly alias, you can include namespaces for each assembly in a wrapper inside the root-level namespaces named for this alias, which allows them to be used in a single file.
...
Each time the extern alias is declared, an additional root-level namespace is introduced, which corresponds to the global namespace (but is not inside it). Thus, references to types from each assembly without ambiguity can be created using their full name, the root of which is the corresponding namespace alias.

Here, however, we should not forget that extern is also used in C # to declare a method with an external implementation from unmanaged code. In this case, extern is usually used with the DllImport attribute. More details about this can be found in the relevant section of the documentation .


So let's try to use our 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; ... } } 

This code is even working. And it works correctly. But still I want to make it a little more elegant. This can be done in a very simple way:


 extern alias Lib1; extern alias Lib2; using System; using SpaceOne=Lib1::Space; using SpaceTwo=Lib2::Space; 

Now you can use the usual and obvious syntax:


 var globe1 = new SpaceOne.Globe() var globe2 = new SpaceTwo.Globe() 

Tests


Let's test our owl:



As you can see, the code worked fine and without errors. The integration of owls and globes successfully completed!


→ Sample code is available on GitHub


')

Source: https://habr.com/ru/post/421851/


All Articles