.NET Standard詳解

.NET Standard是一套協議規範,不像.NET Framework,後者是一個完整的技術框架,而前者只是定義了一套規範,遵守這套規範的.NET Standard類庫可以被不同.NET框架引用,比如.NET Core項目和.NET Framework項目都可以引用這個類庫。

Standard這個單詞就是標準、規範的意思,.NET Standard旨在建立一套標準,解決不同.NET框架之間的兼容性問題。

關於.NET Standard的概念以及版本支持的知識,請大家參考MSDN的介紹:https://docs.microsoft.com/zh-cn/dotnet/standard/net-standard

下面我們用.NET Core和.NET Framework框架爲例介紹.NET Standard爲什麼能解決不同.NET框架之間的兼容性問題

在.NET Core項目中,我們所使用的類所在的程序集從表面上看和.NET Framework是一模一樣的,那既然他們使用的程序集是完全一樣的,爲什麼前者可以跨平臺,而後者不可以呢?關於這個問題,請看我的另一篇文章:.NET Framework類型轉移。

說到這裏,我想到一個問題,爲什麼微軟要使用類型轉移這個技術呢?直接使用對應框架的對應程序集不就可以了嗎。我是這樣想的:因爲.NET Framework框架出來的時間比.NET Core框架出來的時間早很多,微軟爲了讓大家能夠適應.NET Core,所以每個類所在的程序集都沒有變化,但實際上,微軟使用類型轉移技術在背後把原程序集都重定向到了.NET Core的程序集上。這個操作是透明的,所以我們感覺不到。

下面我們用代碼說話吧

我們新建一個.NET Standard的類庫,版本爲2.0。然後新建一個Utils的類,代碼如下:

public class Utils
    {
        public static void PrintAssemblyNames()
        {
            Console.WriteLine(typeof(Dictionary<,>).Assembly.FullName);
            Console.WriteLine(typeof(SortedDictionary<,>).Assembly.FullName);
         
        }
    }

我們輸出了這兩個類型所在的程序集。

然後我們新建兩個項目,一個.NET Framework 4.7.2,一個.NET Core 3.1,這兩個項目都是控制檯程序,代碼如下:

static void Main(string[] args)
        {
            Console.WriteLine(".NET Framework 4.7.2");
            Utils.PrintAssemblyNames();

            Console.ReadKey();
        }
static void Main(string[] args)
        {
            Console.WriteLine(".NET Core 3.1");
            Utils.PrintAssemblyNames();

            Console.ReadKey();
        }

這兩個項目都只做了一件事,在當前項目中輸出上面兩個類所在的程序集的信息。下面我們看一下輸出結果:

可以看到,在不同的項目中輸出的程序集是不一樣的。下面我們就來了解一下爲什麼不一樣。

首先我們看Dictionary類,在.NET Standard項目中,轉到Dictionary的定義,在頁面頂部可以看到它所在的程序集是netstandard。因爲.NET Framework的版本是4.7.2,運行時是CLR4.0,所以我們找到CLR4.0下的netstandard.dll,這個dll在我電腦上的路徑是:C:\Windows\Microsoft.NET\Framework\v4.0.30319\netstandard.dll,找到後使用ildasm.exe打開這個dll,雙擊MANIFEST,點擊查找System.Collections.Generic.Dictionary,可以看到如下代碼:

.class extern forwarder System.Collections.Generic.Dictionary`2
{
  .assembly extern mscorlib
}

這個代碼的意思是System.Collections.Generic.Dictionary類被定義在程序集mscorlib中,所以在.NET Framework4.7.2項目下,Dictionary類所在的程序集是mscorlib。

使用同樣的方法,查找到netstandard在.NET Core下面的路徑:C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.4\netstandard.dll,同樣反編譯這個dll,可以看到如下代碼:

.class extern forwarder System.Collections.Generic.Dictionary`2
{
  .assembly extern System.Collections
}
.class extern forwarder System.Collections.Generic.SortedDictionary`2
{
  .assembly extern System.Collections
}

這兩個類型都被重定向到System.Collections中,但是從輸出結果中可以看到Dictionary的結果集是System.Private.CoreLib,這是爲什麼呢?因爲它被二次轉移了,爲了驗證這個問題,我們在同樣的目錄下找到System.Collections.dll,使用反編譯工具打開這個dll,可以看到如下代碼:

.class extern forwarder System.Collections.Generic.Dictionary`2
{
  .assembly extern System.Private.CoreLib
}

所以在.NET Core的項目中Dictionary類型所在的程序集是System.Private.CoreLib。

其實這裏有個容易被大家忽視的細節,從這個細節也可以看出這兩個類所在的程序集。我們在.NET Core和.NET Framework項目中也定義一個Dictionary類,然後轉到它的定義,可以看出在.NET Core項目中,它所在的程序集是System.Collections,但是因爲有二次轉移,所以最終所在程序集是System.Private.CoreLib;在.NET Framework項目中,它所在的程序集就是mscorlib;但是在.NET Standard項目中,它所在的程序集是netstandard。

.NET Standard類庫之所以能夠兼容其他的.NET框架,就是因爲這個netstandard.dll。在這個項目類庫中所有類型的所在程序集都是netstandard.dll,然後所有的.NET框架也都實現了這個程序集中的類型,通過類型轉移(也稱墊片程序集),最終調用的程序集是引用這個類庫的項目的運行時程序集,這就是.NET Standard能夠兼容其他.NET框架的原因。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章