In essence,. NET, designed by the CLI specification, has a cross-platform gene from the moment it was born, which is indistinguishable with Java. With a unified intermediate language, Microsoft only needs to design different virtual machines (runtimes) for different platforms to bridge the differences between different operating systems and processor architectures, but "the ideal is plump and the reality is very bony." In the past more than 10 years, Microsoft will. NET has been introduced into various application areas and appears to be thriving on the surface, but due to the design of a completely independent multi-objective framework, the code platform for the multi-objective framework can only be passed through the PCL (reference to the ". NET Core cross-platform" mystery [medium]: Reuse of the shame) this "compromise" The way to solve. If we continue to follow this path,. NET tentacles extend more and more shackles, so. NET has come to the point of having to make a radical change.
One, cross-platform. NET Core
To sum up, to truly achieve the cross-platform Albert of. NET, we need to solve two problems, one is to design the corresponding runtime for different platform to provide a consistent execution environment for the intermediate language CIL, but to provide a unified BCL to completely solve the problem of code reuse. For truly cross-platform. NET Core, Microsoft not only designed it to be coreclr for different platforms, but also redesigned a set of BCL called Corefx.
2-221
As shown, there are two main types of Appmodel that are currently supported by NET Core, where ASP. Universal Windows Platform) is used to develop Windows 10 apps that can be adapted to run on a variety of client devices (mobile, PC, Xbox, Devices + IOT, HoloLens, and surface hub, etc.). Corefx is a fully rewritten BCL that, in addition to its ability to cross-platform execution itself, provides APIs that are no longer uniformly defined in a few single assemblies, but are defined in separate modules after being effectively grouped. These modules correspond to a single assembly and are eventually distributed by the corresponding NuGet package. As for the underlying virtual machines, Microsoft has designed a targeted runtime for the main operating system types (Windows, Mac OS x and Linux) and processor architectures (x86, x64, and arm), known as CORECLR.
The coreclr of the runtime and the Corefx that provide the BCL are important cornerstones of. NET core two, but in terms of development costs, Microsoft's commitment to the latter is unmatched. We know that. NET core has been in existence for many years now, the current version is only 2.0, from the release progress appears slightly slow, one of the main reason is: Rewrite Corefx provides a basic API is indeed a tedious time-consuming project, and this project is far from over. To get a general idea of the BCL provided by Corefx, let's look at what namespaces these common base APIs are defined in.
System.Collections: Defines the types of collections we commonly use.
System.Console: Provides APIs to complete basic console operations.
System.Data: Provides APIs for accessing the database, equivalent to the original ADO.
System.Diagnostics: Provides basic diagnostics, debugging, and tracing APIs.
System.DirectoryServices: Provides an API based on AD (Active Directory) management.
System.Drawing: Provides GDI-related APIs.
System.Globalization: Provides APIs for multi-lingual and global support.
System.IO: Provides APIs related to file input and output.
System.Net: Provides APIs related to network communication.
System.Reflection: Provides APIs to implement reflection-related operations.
System.Runtime: Provides some basic types that are related to the runtime.
System.Security: Provides APIs related to data signing and decryption.
System.Text: Provides APIs related to string/text encoding and decoding.
System.Threading: Provides an API for managing threads.
System.Xml: Provides the data that the API uses to manipulate the XML structure.
We know that for the traditional. NET Framework, The APIs hosting the BCL are almost all defined in the mscorlib.dll assembly, not all of which are transferred to the many assemblies that make up the COREFX, and those underlying APIs that are closely related to the runtime (CoreCLR) are defined as a System.Private.CoreLib . dll, so it reflects the true. NET core hierarchy. The basic data types we use during programming are basically defined in this assembly, so the size of this assembly is now more than 10M. Because the API provided by the assembly is more tightly correlated with the runtime, these base APIs are more stable than the APIs provided by Corefx, so it is published with CoreCLR.
2-23
Although most of the underlying types used in our programming are defined in the System.Private.CoreLib.dll assembly, this is a "private" assembly, which we can see from its naming. We refer to System.Private.CoreLib.dll as a private assembly, not that the definition is a private type, but that we do not actually refer to the assembly in the process of programming, which is associated with. NET The mscorlib.dll under the framework are not the same. Not only that, when the. NET core code that we write is compiled, the compiler does not link to the assembly, which means that the compiled assembly does not have the same metadata for that assembly reference. But when our application is actually executed, all referenced base types are automatically "transferred" to this assembly. As for how to achieve the type transfer in the process of operation, we use the type forwarding technology described above.
Example Demo: type transfer for System.Private.CoreLib.dll assemblies
For the type transfer described above for the System.Private.CoreLib.dll assembly, it may be difficult for many people to understand, in order to get a thorough understanding of this problem, we might as well do a simple example demonstration. We use Visual Studio to create a. NET Core console app, and write the following lines of code in the Main method as a program portal, which will take several of our common data types (System.String, The name of the assembly where System.Int32 and System.Boolean are located is printed on the console.
1:class Program
2: {
3:static void Main ()
4: {
5:console.writeline (typeof (String). Assembly.fullname);
6:console.writeline (typeof (int). Assembly.fullname);
7:console.writeline (typeof (BOOL). Assembly.fullname);
8:}
9:}
According to our analysis above, the basic types used in the process of the program are all derived from the System.Private.CoreLib.dll assembly, which is confirmed in the output as shown. With the output shown in Figure 2-24, we know not only the name of the core assembly, but also the current version of the Assembly (4.0.0.0);
2-24
We say that the assembly that is generated after the compilation is applied does not have metadata for the System.Private.CoreLib.dll assembly reference, and in order to prove this, we only need to take advantage of the Windows SDK (in the Directory "%programfiles (x86)% The ildasm.exe of the anti-compilation tools provided by Microsoft Sdks\windows\{version}\bin "is OK. Using Ildasm.exe to open this console application after compiling the compiled assembly, we will find that it has the following applications for both assemblies.
1:. assembly extern System.Runtime
2: {
3:. PublicKeyToken = (B0 3F 5F 7F One-D5 0A 3 a)
4:. Ver 4:2:0:0
5:}
6:. assembly extern System.Console
7: {
8:. PublicKeyToken = (B0 3F 5F 7F One-D5 0A 3 a)
9:. Ver 4:1:0:0
10:}
In fact, our program involves only four types, that is, one console type and three underlying data types (String, Int32, and Boolean). At the assembly level, there is only a reference to the System.Runtime and System.Console assemblies, so there is no doubt that the next three data types are definitely related to the System.Runtime assembly, so what is the definition of the assembly for these three data types? To get the answer, we first need to know where the assembly is stored. We know that "%programfiles%dotnet\" is the application root of. NET core, and this System.Runtime.dll is saved as a "shared" assembly in subdirectories "\shared\microsoft.netcore.app \2.0.0 "below, this directory also holds many other shared assemblies.
We still use the Anti-compilation tool Ildasm.exe to view the metadata definition for the System.Runtime.dll assembly manifest file. We will find that the entire assembly, in addition to defining a few core types (such as two important delegate types, action and func, is defined in this assembly), and its purpose is to take all the underlying types into the type Forwarding is transferred to the System.Private.CoreLib.dll assembly, the following code snippet shows you the relevant definitions for the three basic data type transfers used by our program.
1:. assembly extern System.Private.CoreLib
2: {
3:. PublicKeyToken = (7C EC D7 be A7 8E)
4:. Ver 4:0:0:0
5:}
6:. class extern Forwarder System.String
7: {
8:. assembly extern System.Private.CoreLib
9:}
Ten:. class extern Forwarder System.Int32
11: {
:. assembly extern System.Private.CoreLib
13:}
:. class extern Forwarder System.Boolean
15: {
:. assembly extern System.Private.CoreLib
17:}
We demonstrate the direct reference relationship of the Assembly represented by the instance, and the direction of the transfer of the relevant underlying types (System.String, System.Int32, and System.Boolean) as shown in the above code fragment is basically reflected in the diagram illustrated.
2-25
Reusing. NET Framework Assemblies
The above-mentioned technique of implementing cross-assembly type transfer using the type forwarding method becomes a "gasket (SHIM)", which is an important means of implementing cross-platform multiplexing of assemblies. In addition to the System.runtime.dll,.net core, which provides other shim assemblies, it is from the existence of these shim assemblies that we can use the assemblies compiled in the. NET Framework environment in. NET core applications. In order to let readers have a deep understanding of this, we routinely do a simple example demonstration.
We created an empty solution with Visual Studio and added three items (NetApp, Netcoreapp, NetLib), with NetApp and Netcoreapp respectively for the. NET Framework (4.7) and. Net Core (2.0), while Netlib is a class library project for the. NET framework, the API defined by the project will be called at NetApp and Netcoreapp.
2-26
We defined a Utils tool class in the NETLIB project and defined a Printassemblynames method in it. As shown in the following code snippet, we print out the name of the assembly where the three common types (Task, Uri, and XmlWriter) are located in this method. By invoking this method in applications of different types (. NET Framework and. NET Core), we can determine whether they are loaded from that assembly at run time. We called this method in two different types of console programs, NetApp and Netcoreapp.
NetLib:
1:public class Utils
2: {
3:public static void Printassemblynames ()
4: {
5:console.writeline (typeof (Task). Assembly.fullname);
6:console.writeline (typeof (Uri). Assembly.fullname);
7:console.writeline (typeof (XmlWriter). Assembly.fullname);
8:}
9:}
NETAPP:
1:class Program
2: {
3:static void Main ()
4: {
5:console.writeline (". NET Framework 4.7");
6:utils.printassemblynames ();
7:}
8:}
Netcoreapp:
1:class Program
2: {
3:static void Main ()
4: {
5:console.writeline (". NET Core 2.0");
6:utils.printassemblynames ();
7:}
8:}
After running both the NetApp and Netcoreapp console programs, we will find different output results. As shown, for the three types we specify (System.Threading.Tasks.Task, System.Uri, and System.Xml.XmlWriter), respectively, in the. NET Framework and. Net The assemblies that host them in the core environment are different. Specifically, these three types in the. NET Framework environment are defined in mscorlib.dll, System.dll, and System.Xml.dll, respectively, and when you switch to a. NET core environment, The runtime loads these three types from three private assemblies System.Private.CoreLib.dll, System.Private.Uri.dll, and System.Private.Xml.dll.
2-27
Since both console apps for NetApp and Netcoreapp use the same assembly NetLib.dll for the. NET framework, let's take a look at what assembly references it has with the anti-compilation tool Ildasm.exe. As shown in the following code snippet, the assembly NetLib.dll references an assembly that is consistent with the output from the console app NetApp.
1:. assembly extern mscorlib
2: {
3:. PublicKeyToken = (B7 7A 5C E0 89)
4:. Ver 4:0:0:0
5:}
6:. assembly extern System
7: {
8:. PublicKeyToken = (B7 7A 5C E0 89)
9:. Ver 4:0:0:0
10:}
One:. assembly extern System.Xml
12: {
:. PublicKeyToken = (B7 7A 5C E0 89)
:. Ver 4:0:0:0
15:}
So our core question becomes: How do the three types of Task, Uri, and XmlWriter move to other assemblies in the run environment of. NET Core. To answer this question, we only need to use Ildasm.exe to view mscorlib.dll, System.dll, and System.Xml.dll to decompile the three assemblies. These three assemblies also exist under the "%programfiles%dotnet\\shared\microsoft.netcore.app\2.0.0" directory, and by deserializing the assemblies associated with them, we get the relevant metadata as shown below.
Mscorlib.dll
1:. assembly extern System.Private.CoreLib
2: {
3:. PublicKeyToken = (7C www.huarencai5200.com EC D7 be A7 8E)
4:. Ver 4:0:0:0
5:}
6:. class extern Forwarder System.Threading.Tasks.Task
7: {
8:. assembly extern System.Private.CoreLib
9:}
System.dll
1:. assembly extern System.Private.Uri
2: {
3:. PublicKeyToken = (B0 3F 5F 7F One-D5 0A 3 a)
4:. Ver 4:0:4:0
5:}
6:. class extern Forwarder System.Uri
7: {
8:. assembly extern System.Private.Uri
9:}
System.Xml.dll
1:. assembly extern System.Xml.ReaderWriter
2: {
3:. PublicKeyToken = (www.8555388.cn/B0 3F 5F 7F One-D5 0A 3 a)
4:. Ver 0:0:0:0
5:}
6:. class extern Forwarder System.Xml.XmlWriter
7: {
8:. assembly extern System.Xml.ReaderWriter
9:}
System.Xml.ReaderWriter.dll
1:. assembly extern SYSTEM.PRIVATE.XML
2: {
3:. PublicKeyToken = (CC 7B FF CD 2D DD 51)
4:. Ver 4:0:0:0
5:}
6:. class extern Forwarder System.Xml.XmlWriter
7: {
8:. assembly extern SYSTEM.PRIVATE.XML
9:}
As shown in the code snippet above, the three types of transfers for task, URI, and XmlWriter involve seven assemblies, of which mscorlib.dll, System.dll and System.Xml.dll are three assemblies directly referenced by NetLib.dll, while System.Private.CoreLib.dll, System.Private.Uri.dll and System.Private.Xml.dll are the final hosts of these three types of assemblies. For task and URI types, they only undergo a single transfer, while XmlWriter undergoes two types of transfer, It is transferred to assembly System.Xml.ReaderWriter.dll, which is then transferred to the target assembly System.Private.Xml.dll, and the assembly reference and type transfer relationships are reflected in.
2-28
Second, multi-platform reuse of BCL
While. NET core implements a true cross-platform with CORECLR and Corefx, the current. NET core provides only the two programming models of the ASP, which is designed to achieve unified programming across multiple devices, But still focus on the Windows platform. WPF and Windows Forms for desktop applications under the traditional. NET framework do not have cross-platform implications, so they are still in the future. A large branch of net. In addition to that, while we have a cross-platform ASP. NET Core, traditional ASP. NET is still retained and will continue to upgrade over the next few days. In addition to the. NET Framework and. NET Core,. NET also has another important branch, which is Xamarin, which helps us write unified apps for iOS, OS X, and Android. More than 10 years after the birth of. NET, Microsoft began to be right. NET has a completely new layout that establishes the "unification". NET platform. In general, this so-called unification. NET platform consists of three branches, such as the. NET Framework,. NET core, and Xamarin as shown.
2-29
Although it was re-layout by Microsoft. NET platform contains only three branches, but one of the important problems encountered before is the reuse of code, and more specifically, it should be the reuse of the Assembly rather than the reuse of the source code. We know that before the solution to the Assembly service is PCL, but this is not an ideal solution, because each target framework has a variety of independent BCL, so we create a PCL project can only be built on the specified several compatible target framework of the BCL intersection. For the brand-new. NET platform, this issue is fundamentally addressed by providing a unified BCL, a unified BCL called. NET Standard.
The portability capabilities that the. NET standard is called a new generation of PCL,PCL are limited to the few target platforms that were identified at the time of creation, but. NET standard is more thorough because it has been designed with a view to reusing three major branches. As shown in. NET Standard provides a unified API for the. NET Framework,. NET core, and Xamarin, the code that we write on the basis of this standardized set of APIs can be reused by all types of. NET Applications.
2-30
The API provided by. NET Standard is primarily defined by the existing. NET Framework, and its version upgrade reflects the growing process of the API it provides, the latest version (. NET Standard 2.0) The number of APIs provided has almost doubled on the basis of the previous version. Visual Studio provides the appropriate project template to help us create a. NET standard-based class library project that uses a dedicated target framework alias, netstandard{version}. A class library project for. NET Standard 2.0 has the following definition, and we can see that it uses the target framework alias of ". NET Standard 2.0".
1: <project sdk= "MICROSOFT.NET.SDK" >
2: <PropertyGroup>
3: <TargetFramework>netstandard2.0<www.jpg157.com/TargetFramework>
4: </PropertyGroup>
5: </Project>
As the name implies,. NET Standard is just a criterion, not a specific implementation. We can simply understand that. NET standard defines a complete set of interfaces for us, and each branch needs to provide implementations for its own execution environment for that interface. For. NET core, its underlying API is primarily hosted by the core assembly of Corefx and System.Private.CoreLib.dll, which are basically designed to be based on. NET Standard. However, for the. NET Framework, the APIs provided by the BCL have a large intersection with. NET Standard, in fact. NET Standard is basically designed according to the existing API of the. NET Framework, so Microsoft cannot The framework overrides a set of implementations of type Corefx, simply using a technology "link" to an existing assembly.
An assembly built for. NET Standard compilation in a different execution environment for the so-called "link" to a truly implemented assembly is still implemented by the "shim" technology we described above, to get a thorough understanding of the problem, let's start with a simple example demonstration. As shown, we have created a solution that has a similar structure to the demo instance above, and differs from that for the. NET Framework and. Net The core console application of the class library referenced by NetApp and Netcoreapp Netstandardlib is a. NET Standard 2.0 Class library project.
2-31
As in the example shown above, we defined the following Utils class in Netstandardlib and printassemblynames data two data types using the static methods defined therein (dictionary<,> and sorteddictionary<,>) are located in the assembly name, which is called in the main method of the ingress of NetApp and Netcoreapp respectively.
Netstandardlib:
1:public class Utils
2: {
3:public static void Printassemblynames ()
4: {
5:console.writeline (typeof (Dictionary<,www.mayiyule158.cn >). Assembly.fullname);
6:console.writeline (typeof (Sorteddictionary<,>). Assembly.fullname);
7:}
8:}
NETAPP:
1:class Program
2: {
3:static void Main (www.feihuanyule.com)
4: {
5:console.writeline (www.feityl.com ". NET Framework 4.7");
6:utils.printassemblynames ();
7:}
8:}
Netcoreapp:
1:class Program
2: {
3:static void Main ()
4: {
5:console.writeline (www.longboshyl.cn ". NET Core 2.0");
6:utils.printassemblynames (www.wangcai157.com);
7:}
8:}
Running both NetApp and Netcoreapp for the. NET Framework and. NET core respectively, we will find that they produce different output results. As shown in the. NET Framework and the. NET Core execution Environment, the other generic dictionary types,dictionary<,> and sorteddictionary<,> are actually derived from different assemblies. Specifically, the dictionary<,> types we use are in the. NET Framework 4.7 and. NET Core 2.0 environments are defined separately in assemblies mscorlib.dll and System.Private.CoreLib.dll, and sorteddictionary<,> The assemblies in which they are located are System.dll and System.Collection.dll, respectively.
2-32
For this example of the demo, the Netstandardlib Class library project targets the. NET Standard 2.0, the latter is eventually shown as a NuGet package called NetStandard.Library.nupkg, which can actually be seen from Visual Studio's dependency node for the project. As shown, this NuGet package named Netstandard.library has a core assembly of Netstandard.dll, which is defined in the. NET standard API as described above.
2-33
That is, all. NET Standard 2.0 projects have a dependency on assembly Netstandard.dll, a dependency that naturally manifests itself on compiled assemblies. For this class library project in our demo instance, netstandardlib compiles the generated assembly with the same name, its dependency on assembly Netstandard.dll is reflected in the metadata shown below.
1:. assembly extern Netstandard
2: {
3:. PublicKeyToken = (CC www.wangcai157.com 7B FF CD 2D DD)
4 :. Ver 2:0:0:0
5:}
6:. Assembly Netstandardlib
7: {
8: ...
9:}
10: ...
According to our knowledge, the two types (dictionary<,> and sorteddictionary<,>) that were originally defined in netstandard.dll need to be transferred to another assembly in a different execution environment. We can provide a shim assembly of the same name in the appropriate environment and implement it with a type of cross-assembly transfer mechanism, which is what Microsoft actually does. Let's take a look at the relevant definitions for the. NET Framework Shim Assembly Netstandard.dll, which we can find directly in the NetApp compiled target directory. With the help of the Anti-compilation tool Ildasm.exe, we can easily get the relevant metadata for the transfer of the two generic dictionary types, dictionary<,> and sorteddictionary<,>, as shown in the following code snippet.
1:. assembly extern mscorlib
2: {
3:. PublicKeyToken = (B7 7A 5C 5 E0)
4:. Ver 0:0:0:0
:
6:. assembly extern System
7: {
8:. PublicKeyToken = (B7 7A 5C E0)
9:. Ver 0:0:0:0
10:
One:. class extern forwarder System.Collections.Concurrent.ConcurrentDictionary ' 2
: {
:. Assembly Exter n mscorlib
:}
:. class extern forwarder System.Collections.Generic.SortedDictionary ' 2
: {
:. Asse mbly extern System
:}
Shim assemblies for. NET core Netstandard.dll are saved in the shared directory we mentioned earlier "%programfiles%dotnet\shared\ microsoft.netcore.app\2.0.0, we use the same approach to extract metadata that is transferred from the two generic dictionary types, dictionary<,> and sorteddictionary<,>. From the code snippet below we can clearly see that both,dictionary<,> and sorteddictionary<,> are transferred to the Assembly System.Collections.dll.
1:. assembly extern System.Collections
2: {
3:. PublicKeyToken = (B0 3F 5F 7F D5 0A 3 A)
4:. Ver 0:0:0 : 0
5:}
6:. class extern forwarder System.Collections.Generic.Dictionary ' 2
7: {
8:. assembly extern System . Collections
9:}
:. class extern forwarder System.Collections.Generic.SortedDictionary ' 2
One: {
:. embly extern system.collections
:}
from the execution results of the demo instance we know,sorteddictionary<,> is really defined in the assembly System.Collections.dll, but our usual dictionary<,> Type is derived from the core assembly System.Private.CoreLib.dll, then we can conclude that the dictionary<,> type must have two transitions in System.Collections.dll. To confirm our assertion, we only need to decompile the assembly System.Collections.dll the same way, and the assembly is also stored in the shared directory "%programfiles%dotnet\shared\ microsoft.netcore.app\2.0.0, the transition for the dictionary<,> type in the assembly is reflected in the metadata shown below.
1:. assembly extern System.Private.CoreLib
2: {
3:. PublicKeyToken = (7C EC D7 be A7 8E)
4:. Ver 4:0:0:0
5:}
6:. class extern forwarder System.Collections.Generic.Dictionary ' 2
7: {
8:. assembly extern System.Private.CoreLib
9:}
The cross-assembly transfer paths for dictionary<,> and sorteddictionary<,>, respectively, in the. NET Framework 4.7 and. NET core environments, are basically reflected. In a nutshell, the Shim assembly Netstandard.dll in the. NET framework environment transfers these two types to assemblies mscorlib.dll and System.dll respectively. If the execution environment switches to. NET Core, these two types are first transferred to System.Collection.dll, but dictionary<,> This common type is ultimately hosted by the System.Private.CoreLib.dll base assembly, which has been transferred two times in all System.Collection.dll.
2-34
This simple type above basically reveals why. NET Standard can provide full platform portability, and now we're going to make a simple summary of that.. NET Standard The API is hosted by Netstandard.library, the NuGet package, which provides an assembly called Netstandard.dll, which retains only the stub of the. NET Standard API in this assembly. Rather than providing a concrete implementation. All assembly-generated assemblies for a class library project with a target framework of. NET Standard retain a reference to assembly Netstandard.dll.
. The three major branches of the net platform (. NET Framework,. NET core, and Xamarin) implement this standard set of APIs in their own way. Because the types that actually host the. NET standard API at run time are distributed across multiple assemblies, so. NET standard assemblies can be reused if the runtime is able to link these underlying types to the corresponding assemblies. Because. NET standard assemblies are compiled for Netstandard.dll, so we only need to provide the same assembly with the same name in the respective environment to complete the transfer of the type.
The mysteries of the. NET Core cross-platform [prev]: The shackles of history
The mysteries of the. NET Core cross-platform [medium]: The War of Reuse
The mysteries of the. NET Core cross-platform [next]: New layouts
NET Core cross-platform mystery [medium]: The War of Reuse