
Heute Abend begann gelas ein Gespräch darüber, wie Paketmanager auf verschiedenen Plattformen arbeiten. Während des Gesprächs kamen wir zu einer Diskussion über die Situation, in der Sie zwei Bibliotheken mit dem .NET Core-Projekt verbinden müssen, die Klassen mit demselben Namen im selben Namespace enthalten. Da ich ziemlich viel .NET Core mache, wollte ich überprüfen, wie dieses Problem gelöst werden kann. Was dabei herauskam, wird weiter beschrieben
Haftungsausschluss . Treten solche Situationen häufig auf? Seit mehr als 10 Jahren mit .NET habe ich mich in einem realen Projekt nie mit einer ähnlichen Situation befasst. Aber das Experiment war interessant.
Für alle Fälle werde ich klarstellen, dass ich das Experiment durchführen werde mit:
- macOS 10.13,
- .NET Core SDK 2.1.302
- Fahrer 2018.2
Wir werden also eine Situation simulieren, in der wir zwei Bibliotheken haben, die die Klassen haben, die wir brauchen, die wir in unserem Projekt verwenden müssen. Gleichzeitig haben wir keinen Zugriff auf den Quellcode, können jedoch die Assemblys nicht dekompilieren, um den Namespace in ihnen zu ändern, und können dann auch nicht zurückkompilieren.
Versuchsvorbereitung
Bereiten Sie für den Anfang eine Eule und zwei Globen vor. Als Eule werden wir ein Projekt haben, das auf netcoreapp2.1 abzielt. Wir werden zwei Projekte als Globen erstellen, von denen eines auch auf netcoreapp2.1 und das zweite auf netstandard2.0 abzielt

In jedem Projekt platzieren wir die Globe-Klasse, die sich in identischen Namespaces befindet, jedoch unterschiedliche Implementierungen aufweist:
Erste Datei:
using System; namespace Space { public class Globe { public string GetColor() => "Green"; } }
Zweite Datei:
using System; namespace Space { public class Globe { public string GetColor() => "Blue"; } }
Versuch Nummer eins
Da wir gemäß den Bedingungen des Problems mit externen Assemblys und nicht mit Projekten arbeiten sollten, werden wir dem Projekt entsprechend Links hinzufügen, als wären sie wirklich nur Bibliotheken. Kompilieren Sie dazu zunächst alle Projekte so, dass wir die Globe1.dll und Globe2.dll haben, die wir benötigen. Fügen Sie dann im Projekt wie folgt Links hinzu:

Versuchen Sie nun, eine Globe-Klassenvariable zu erstellen:

Wie Sie sehen, warnt uns die IDE bereits zu diesem Zeitpunkt, dass es ein Problem mit dem Verständnis gibt, woher die benötigte Globe-Klasse stammen sollte.
Auf den ersten Blick scheint die Situation recht typisch zu sein und es sollte bereits eine fertige, in Granit gegossene Antwort auf Stack Overflow geben. Wie sich herausstellte, wurde für .NET Core noch keine Lösung für dieses Problem vorgeschlagen. Oder mein Google hat mich im Stich gelassen. Aber ich habe es geschafft, etwas Nützliches für Stack Overflow zu finden. Die einzige vernünftige Veröffentlichung, die ich googeln konnte, war 2006 und beschrieb eine ähnliche Situation für die klassische Version von .NET. In diesem Fall wird ein sehr ähnliches Problem im Repository des NuGet-Projekts erörtert.
Bisher nicht viele nützliche Informationen, aber es ist immer noch da:
- In der klassischen Version von .NET wurde ein Alias-Mechanismus implementiert
- Gemäß der Spezifikation unterstützt C # die Verwendung von Aliasen im Code
Es bleibt zu verstehen, wie dies in .NET Core gemacht wird.
Leider spricht die aktuelle Version der Dokumentation eher bescheiden über die Möglichkeiten, externe Pakete / Gebühren anzuschließen. Und die Beschreibung der csproj-Datei gibt auch keinen Aufschluss über die Möglichkeit, Aliase zu erstellen. Trotzdem konnte ich durch Ausprobieren herausfinden, dass Aliase für Assemblys in .NET Core weiterhin unterstützt werden. Und sie sind wie folgt aufgebaut:
<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>
Nun bleibt zu lernen, wie diese Aliase verwendet werden. Das zuvor erwähnte externe Schlüsselwort hilft uns dabei:
Folgendes ist in der Dokumentation dazu geschrieben:
In einigen Fällen müssen Sie möglicherweise auf zwei Versionen von Assemblys mit denselben vollständig qualifizierten Typnamen verweisen. Beispielsweise müssen Sie zwei oder mehr Versionen einer Baugruppe in einer Anwendung verwenden. Mithilfe eines externen Assemblyalias können Sie Namespaces für jede Assembly in einem Wrapper in die von diesem Alias benannten Namespaces auf Stammebene einfügen, sodass Sie sie in einer einzelnen Datei verwenden können.
...
Jede Deklaration eines externen Alias führt einen zusätzlichen Namespace auf Stammebene ein, der dem globalen Namespace entspricht (sich jedoch nicht darin befindet). Somit können Verweise auf Typen aus jeder Assembly ohne Mehrdeutigkeit unter Verwendung ihres vollständigen Namens erstellt werden, dessen Stamm der entsprechende Namespace-Alias ist.
Die Wahrheit hier ist nicht zu vergessen, dass extern auch in C # verwendet wird, um eine Methode mit einer externen Implementierung aus nicht verwaltetem Code zu deklarieren. In diesem Fall wird extern normalerweise mit dem DllImport-Attribut verwendet. Weitere Informationen hierzu finden Sie im entsprechenden Abschnitt der Dokumentation .
Versuchen wir also, unsere Aliase zu verwenden:
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; ... } }
Dieser Code funktioniert sogar schon. Und es funktioniert richtig. Trotzdem möchte ich es etwas eleganter machen. Dies kann auf sehr einfache Weise erfolgen:
extern alias Lib1; extern alias Lib2; using System; using SpaceOne=Lib1::Space; using SpaceTwo=Lib2::Space;
Jetzt können Sie die übliche und offensichtliche Syntax verwenden:
var globe1 = new SpaceOne.Globe() var globe2 = new SpaceTwo.Globe()
Test
Testen wir unsere Eule:

Wie Sie sehen können, hat der Code einwandfrei und fehlerfrei funktioniert. Die Integration von Eulen und Globen wurde erfolgreich abgeschlossen!
→ Beispielcode ist auf GitHub verfügbar