.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框架的原因。

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值