چگونه از دو نگارش مختلف یک اسمبلی در برنامه‌های NET Core. استفاده کنیم؟
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: سه دقیقه

فرض کنید اسمبلی A که System.Drawing.Common، نام دارد، فضای نام System.Drawing.Common را ارائه می‌دهد و اسمبلی B که CoreCompact.System.Drawing نام دارد، باز هم دقیقا همان فضای نام را ارائه می‌دهد. سؤال: آیا می‌توان از این دو اسمبلی مختلف در برنامه‌ی خود استفاده کرد؟ یا مثال دیگر آن داشتن دو اسمبلی با نگارش‌های مختلف، از یک کتابخانه است. برای مثال یکی بر اساس netcoreapp2.1 تهیه شده‌است و دیگری بر اساس netstandard2.0 و به هر دلیلی نیاز است که بتوان از هر دو اسمبلی در برنامه‌ی خود استفاده کرد. برای یک چنین مواردی در زبان #C ویژگی به نام extern alias وجود دارد که با مثالی نحوه‌ی کار با آن‌را بررسی خواهیم کرد.


ایجاد پروژه‌ی Globe1

پروژه‌ی کتابخانه‌ی Globe1 را بر اساس netcoreapp2.1 به این صورت توسط فایل‌های زیر ایجاد می‌کنیم:

الف) فایل Globe1.csproj
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>netcoreapp2.1</TargetFramework>
    </PropertyGroup>
</Project>

ب) فایل Globe.cs
using System;

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


ایجاد پروژه‌ی Globe2

پروژه‌ی کتابخانه‌ی Globe2 را بر اساس netstandard2.0 به این صورت توسط فایل‌های زیر ایجاد می‌کنیم:

الف) فایل Globe2.csproj
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
    </PropertyGroup>
</Project>

ب) فایل Globe.cs
using System;

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


ایجاد یک پروژه‌ی کنسول استفاده کننده‌ی از این اسمبلی‌ها

همانطور که ملاحظه می‌کنید اگر این دو پروژه‌ی class library را کامپایل کنیم، به دو فایل dll یا اسمبلی خواهیم رسید که هر دو دارای فضای نام Space و همچنین کلاس Globe هستند. اما نگارش‌های آن‌ها و یا TargetFrameworkهای آن‌ها متفاوت است. اکنون می‌خواهیم از هر دوی این‌ها در یک پروژه‌ی Console استفاده کنیم. بنابراین ابتدا این پروژه را با ایجاد فایل csproj آن شروع می‌کنیم:

الف) فایل Owl.csproj
<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\$(Configuration)\netcoreapp2.1\Globe1.dll</HintPath>
            <Aliases>Lib1</Aliases>
        </Reference>

        <Reference Include="Globe2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
            <HintPath>..\Globe2\bin\$(Configuration)\netstandard2.0\Globe2.dll</HintPath>
            <Aliases>Lib2</Aliases>
        </Reference>
    </ItemGroup>
</Project>
روش ارجاع دهی به این اسمبلی‌ها، اندکی متفاوت است. در اینجا نام هر کدام به همراه شماره نگارش آن‌ها ذکر شده‌است. همچنین مسیر یافتن فایل‌های Globe1.dll و Globe2.dll نیز ذکر شده‌اند؛ بجای اینکه ارجاعی را به فایل‌های csproj این class libraryها اضافه کنیم (از این جهت که ممکن است مانند مثال ابتدای بحث، صرفا دو فایل dll را بیشتر در اختیار نداشته باشیم). به علاوه یک Alias نیز برای هر کدام تعریف شده‌است تا توسط آن بتوان به امکانات هرکدام دسترسی یافت. وجود این Alias از این جهت ضروری است که هرچند دو فایل dll مختلف را داریم، اما فضاهای نام و کلاس‌های آن‌ها، نام‌های مشابهی دارند و قابل تمیز از یکدیگر نیستند.

ب) فایل Program.cs

اکنون قسمت مهم این فایل، همان extern aliasهایی هستند که پیشتر تعریف کردیم:
extern alias Lib1;
extern alias Lib2;
using System;
using SpaceOne = Lib1::Space;
using SpaceTwo = Lib2::Space;

namespace Owl
{
    class Program
    {
        static void Main(string[] args)
        {
            var owl = new SuperOwl();
            owl.IntegrateGlobe(new SpaceOne.Globe());
            owl.IntegrateGlobe(new SpaceTwo.Globe());

            Console.WriteLine(owl.GetGLobeColors());
        }
    }

    public class SuperOwl
    {
        private SpaceOne.Globe _firstGlobe;
        private SpaceTwo.Globe _secondGlobe;

        public void IntegrateGlobe(SpaceOne.Globe globe) => _firstGlobe = globe;
        public void IntegrateGlobe(SpaceTwo.Globe globe) => _secondGlobe = globe;
        public string GetGLobeColors() => $"First: {_firstGlobe.GetColor()}, Second: {_secondGlobe.GetColor()}";
    }
}
ابتدا extern aliasها تعریف می‌شوند:
extern alias Lib1;
extern alias Lib2;
 سپس بر اساس هر Alias می‌توان یک فضای نام جدید را بجای فضای نام Space فعلی هرکدام تعریف کرد:
using SpaceOne = Lib1::Space;
using SpaceTwo = Lib2::Space;
 تا بتوان به متدهای GetColor متفاوت این‌ها دسترسی یافت.

اگر این برنامه را اجرا کنیم، چنین خروجی حاصل می‌شود:
First: Blue, Second: Green

کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید: alias.zip