Главная » Хабрахабр » Проблематика совы и глобуса: подключение двух сборок с идентичными пространствами имен и названиями классов

Проблематика совы и глобуса: подключение двух сборок с идентичными пространствами имен и названиями классов

В ходе беседы, дошли до обсуждения ситуации, когда в проект на . Сегодня вечером, с gelas завели разговор о том, как работают пакетные менеджеры на разных платформах. Поскольку . NET Core необходимо подключить две библиотеки, которые содержат классы с одинаковым названием в одинаковых пространствах имен. Что из этого вышло описано дальше NET Core я занимаюсь достаточно плотно, я захотел проверить, как можно решить подобную проблему.

Часто ли встречаются такие ситуации? Дисклеймер. NET, с подобной ситуацией в реальном проекте не приходилось сталкиваться ни разу. Мне за более чем 10 лет работы с . Но вот провести эксперимент было интересно.

На всякий случай уточню, что эксперимент я буду проводить используя:

  • macOS 10.13,
  • .NET Core SDK 2.1.302
  • Rider 2018.2

При этом доступ к исходному коду у нас нет, а декомпилировать это сборки, чтобы поменять в них неймспейсы, а потом скомпилировать обратно мы тоже не можем. Итак, смоделируем ситуацию, когда к нам попали две библиотеки, в которых есть необходимые нам классы, которые мы должны использовать в нашем проекте.

Подготовка эксперимента

В качестве совы у нас будет выступать проект с таргетом на netcoreapp2. И так, для начала подготовим одну сову и два глобуса. В качестве глобусов создадим два проекта, один из готорых будет также с таргетом на netcoreapp2. 1. 1, а второй на netstandard2.

В каждый проект поместим по классу Globe, которые будут находится в идентичных неймспейсах, но реализация при этому у них будет разная:

Первый файл:

using System; namespace Space

}

Вторй файл:

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

Попытка номер один

Для этого сначала скомпилируем все проекты, чтобы у нас появились нужные нам Globe1.dll и Globe2.dll. Поскольку по условиям задачи мы должны работать с внешними сборками, а не проектами, то добавим соответственно в проект ссылки как будто они действительно являются просто библиотеками. Затем добавим на них ссылки в проект в таком виде:

Теперь попробуем создать переменную класса Globe:

Как видим, уже на этом этапе IDE предупреждает нас о том, что есть проблема с пониманием того, откуда должен быть взят нужный нам класс Globe.

Как оказалось, для . Сначала кажется, что ситуация довольно типичная и на нее уже должны быть готовый, отлитый в граните, ответ на Stack Overflow. Либо мой Гугл меня подвел. NET Core решения подобной задачи пока еще предложено не было. NET. Но кое что полезное на Stack Overflow найти удалось.Единственная толковая публикация, которую удалось нагуглить — была за 2006 год и описывала подобную ситуацию для классической версии . При этом, весьма похожа проблема обсуждается в репозитории проекта NuGet.

Пока не очень много полезно информации, но она все же есть:

NET Core. Осталось понять, как сделать это в .

А описание csproj файла также никоим образом не проливает свет на возможности создания псевдонимов. К сожалению, в текущей версии документации довольно скромно рассказывается о возможностях подключения внешних пакетов/сборов. NET Core все-таки поддерживаются. Но тем не менее, методами проб и ошибок, мне удалось выяснить, что псевдонимы для сборок в . И оформляются они следующем образом:

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

В этом нам поможет ранее уже упоминаемое ключевое слово extern: Теперь осталось научиться использовать эти псевдонимы.

В документации о нем пишут следующее:

Например, вам необходимо использовать две или более версий сборки в одном приложении. В некоторых случаях может потребоваться задать ссылки на две версии сборок с одинаковыми полными именами типов. Таким образом ссылки на типы из каждой сборки без неоднозначности могут создаваться с помощью их полного имени, корнем которого является соответствующий псевдоним пространства имен. С помощью внешнего псевдонима сборки можно включить пространства имен для каждой сборки в оболочку внутри пространств имен корневого уровня, именуемых по этому псевдониму, что позволяет использовать их в одном файле.

При каждом объявлении псевдонима extern вводится дополнительное пространство имен корневого уровня, которое соответствует глобальному пространству имен (но не находится внутри него).

В этом случае extern обычно используется с атрибутом DllImport. Тут правда не стоит забывать о том, что extern также используется в C# для объявления метода с внешней реализацией из неуправляемого кода. Более детально об этом можно почитать в соответствующем разделе документации.

Итак, попробуем использовать наши псевдонимы:

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; ... }
}

Причем работает правильно. Этот код уже даже работает. Сделать это можно весьма простым способом: Но все-таки хочется сделать его чуточку элегантнее.

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

Теперь можно использовать обычный и очевидный синтаксис:

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

Испытания

Проведем испытания нашей совы:

Интеграция совы и глобусов успешно завершена! Как видим, код отработал нормально и без ошибок.

→ Код примера доступен на GitHub


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

Фулстеки — это вечные мидлы. Не идите по этому пути, если не хотите страдать

У меня появилась идея фикс — быть разработчиком, который может всё. Когда я только начал учиться кодить, я поверил старым мудрым засранцам с их мантрой «язык программирования не важен». Но эта затея с треском провалилась. Парнем, который переносит опыт использования ...

«Я просто энтузиаст проекта и пользователь языка Dart» — интервью с Ari Lerner, автором знаменитой ng-book

Что самое важное в обучении, что такое «hallway chat» и вообще, при чём тут Dart и Flutter? Как написать девять книг по совершенно разным технологиям, включая Angular, Vue, React, React Native и другим? Какой будет дальнейшая книга, что автор думает ...