Inside Portable Class Libraries
Portable Class Libraries were introduced with Visual Studio 2010 SP1 to aid writing libraries that could be used on many different platforms – the full .NET 4/4.5 framework, Windows Phone, Silverlight, Xbox, and Windows Store apps. You simply select which platforms and versions you want to target, then the available subset of APIs are magically available. But how does it work? How does Visual Studio know what it can target, and how does the same assembly run on many different platforms? Today, I’ll be finding out.
Creating a Portable Class Library
When you create a PCL in Visual Studio, you select the platforms and versions you want to target. In this example, I’ve selected everything at the lowest available version. In the project references list, this turns into a generic ‘.NET Portable Subset’, with no real identifying information as to what it actually is:

Hmm, ok, well lets see what the actual built assembly does with it. Lets create a field of type Action<T1,T2> so the assembly actually has something in it:
public class Class1 {
Action<int, double> action = null;
}
After building the assembly, and opening it up in a decompiler, we can see that that mysterious ‘.NET Portable Subset’ reference has turned into standard assembly references to mscorlib.dll and System.Core.dll. However, they look a bit odd:
mscorlib, Version=2.0.5.0, Culture=neutral,
PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes
System.Core, Version=2.0.5.0, Culture=neutral,
PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes
2.0.5.0 is the version number used by Silverlight assemblies, and that’s the Silverlight public key, but that ‘Retargetable’ flag is new. And if you have a look at the assembly-level attributes, you’ll spot something familiar:
[assembly: TargetFramework(
".NETPortable,Version=v4.0,Profile=Profile1",
FrameworkDisplayName=".NET Portable Subset")]
Aha! There’s the ‘.NET Portable Subset’ from the Visual Studio reference list. But what about the target framework? ".NETPortable,Version=v4.0,Profile=Profile1"? What’s that all about? Well, have a look in ‘C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.0\Profile\’. In there is a list of every possible .NET 4 PCL subset you can target (22 in total). Within each profile directory are the available assemblies containing the types that can be used, and an xml file for each framework supported by that profile containing platform version information.
These profile directories have been pre-calculated by Microsoft and installed alongside visual studio. When you create a PCL project, and select the platforms and versions you want supported, Visual Studio looks at all the available profiles and the framework versions they are valid for. From the version and platform information in each profile it works out the most applicable profile, and dlls in that profile are the ones it compiles the PCL assembly against and to provide intellisense support.
But these dlls are useless at runtime. If you open one of the dlls in a decompiler, you’ll see that all the method bodies are empty or simply return the default value for the return type. These dlls exist only to be referenced and compiled against.
Using a portable class library
So the dlls in the Reference Assemblies folder are, rather unsuprisingly, only to be referenced. Something else happens at runtime to make the portable library work on all the supported frameworks.
It turns out that it all comes down to a feature of .NET assemblies that was introduced in .NET 2, and I looked at two years ago – type forwards. In the portable class library I’ve built, the System.Action`2 type I’ve used has been resolved to the System.Core assembly. In different platforms, it may be in different places. But every platform will either contain the type in System.Core, or System.Core will have a type forward to where the type is actually located.
So, as you’ll see in the framework-specific reference assemblies, Silverlight 4, Windows Phone, and Xbox all have System.Action`2 located in their System.Core.dll, so the type is resolved successfully on those platforms. Both the desktop and Silverlight 5 System.Core.dll have a type forward for System.Action`2 to the relevant mscorlib.dll, where the type is actually located.
Windows store applications (the framework for windows store applications is called ‘.NETCore’) forward the type to System.Runtime.dll. And, if you take a further look at the System.Core.dll in the .NETCore framework, this assembly contains no types whatsoever! The only things in that assembly of any note are a series of type forwards to various other assemblies in the .NETCore framework – that assembly exists only to redirect type references in portable class libraries when they are used in Windows Store applications.
Cross-version assembly references
There is one more thing we need to sort out. If you have a look at the assembly references in the original PCL we built, they reference a specific version of mscorlib.dll and System.Core.dll:
mscorlib, Version=2.0.5.0, Culture=neutral,
PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes
System.Core, Version=2.0.5.0, Culture=neutral,
PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes
These versions are the same as the version numbers on Silverlight 4, Windows Phone, and Xbox framework assemblies. But the version of mscorlib for Silverlight 5 is:
mscorlib, Version=5.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
and .NET 4 desktop and .NETCore:
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
This is a problem. These assemblies all have strong name signatures, and the version & public key form part of the assembly’s identity. An assembly reference to an assembly with version 2.0.5.0 and public key 7cec85d7bea7798e cannot be resolved to an assembly with version 4.0.0.0 and public key b77a5c561934e089. To the CLR, these are two completely different assemblies.
That’s where the Retargetable flag on the assembly references comes in. If this flag is on an assembly reference, it means the reference can resolve to an assembly with a different version and public key, even though it is technically a different assembly. This flag is on all the references to framework dlls in a PCL, and this means the PCL can run on different frameworks with different assembly versions and public keys. The framework dll references are resolved to the one available in the framework the library is executing on at runtime.
Conclusion
There’s nothing magic about portable class libraries. They are compiled just like any other assembly, but are compiled against a specific pre-defined subset of the libraries available in the different frameworks, defined by portable profiles representing the various combinations of types and methods available. When the library is executing on a specific framework at runtime, type fowards redirect any types that have been moved to a different assembly in that framework. The common CLR, assembly metadata and IL formats across all the frameworks and versions ensure the actual code logic in the assembly executes the same way on any available framework.
from:https://www.simple-talk.com/blogs/2013/04/19/inside-portable-class-libraries/
Inside Portable Class Libraries的更多相关文章
- How to Make Portable Class Libraries Work for You
A Portable Class Library is a .NET library that can be used (in binary form, without recompiling) on ...
- The .NET of Tomorrow
Ed Charbeneau(http://developer.telerik.com/featured/the-net-of-tomorrow/) Exciting times lie ahead f ...
- DotNet 资源大全中文版(Awesome最新版)
Awesome系列的.Net资源整理.awesome-dotnet是由quozd发起和维护.内容包括:编译器.压缩.应用框架.应用模板.加密.数据库.反编译.IDE.日志.风格指南等. 算法与数据结构 ...
- A Complete List of .NET Open Source Developer Projects
http://scottge.net/2015/07/08/a-complete-list-of-net-open-source-developer-projects/?utm_source=tuic ...
- [译]Introducing ASP.NET vNext and MVC 6
原文:http://www.infoq.com/news/2014/05/ASP.NET-vNext?utm_source=tuicool Part of the ASP.NET vNext init ...
- visual studio 2013 配置开发环境
https://www.visualstudio.com/explore/xamarin-vs http://sourceforge.net/projects/easyeclipse/files/?s ...
- Introducing ASP.NET vNext and MVC 6
[译]Introducing ASP.NET vNext and MVC 6 原文:http://www.infoq.com/news/2014/05/ASP.NET-vNext?utm_source ...
- .NET 开源开发项目【翻译】
原文地址 本文列出了 .NET 开源开发项目(open source developer projects).意在包括对开发过程的所有方面有所帮组的项目.对于消费项目(consumer project ...
- Go 2 Draft Designs
Go 2 Draft Designs 28 August 2018 Yesterday, at our annual Go contributor summit, attendees got a sn ...
随机推荐
- java多线程-读写锁原理
Java5 在 java.util.concurrent 包中已经包含了读写锁.尽管如此,我们还是应该了解其实现背后的原理. 读/写锁的 Java 实现(Read / Write Lock Java ...
- InnoDB 锁
参看文章: innodb的意向锁有什么作用? 2.<MySQL技术内幕:InnoDB存储引擎> InnoDB存储引擎中的锁 InnoDB中的锁介绍 InnoDB存储引擎既支持行级锁,也支持 ...
- SQL Server 2000 系统存储过程
SQL Server 2000 系统存储过程 在 Microsoft? SQL Server? 中,许多管理和信息活动可以通过系统存储过程执行.系统存储过程按这些分类分组. 分类 描述 Active ...
- Python学习笔记:import sys模块(argv、path、platform、exit)
sys模块是Python标准库中自带的一个模块. sys模块包括了一组非常实用的服务,内含很多函数方法和变量,用来处理Python运行时配置以及资源,从而可以与当前程序之外的系统环境交互,如:Pyth ...
- **PHP错误Cannot use object of type stdClass as array in错误的
错误:将PHP对象类型当做了PHP数组 解决方法:用对象操作符-> 今天在PHP输出一个二维数组的时候,出现了“Fatal error: Cannot use object of type s ...
- javascript和jquery如何判断元素是否存在最佳。
在传统的Javascript里,当我们对某个页面元素进行某种操作前,最好先判断这个元素是否存在.原因是对一个不存在的元素进行操作是不允许的.例如: document.getElementById(&q ...
- Ionic实战六:日期选择控件
onic日期选择控件,用于ionic项目开发中的日期选择以及日期插件   
- shell script执行的几种方式
编写一个shell脚本test.sh,内容如下 a='测试执行方式' echo $a 方式1 使用路径的方式执行 chmod a+x test.sh ./test.sh 执行结果如下 当脚本执行之后, ...
- 深度学习基础系列(九)| Dropout VS Batch Normalization? 是时候放弃Dropout了
Dropout是过去几年非常流行的正则化技术,可有效防止过拟合的发生.但从深度学习的发展趋势看,Batch Normalizaton(简称BN)正在逐步取代Dropout技术,特别是在卷积层.本文将首 ...
- 300万大奖:欢迎参加美团联合主办的全球AI挑战赛
2018年8月29日,由美团.创新工场.搜狗.美图联合主办的“AI Challenger 2018全球AI挑战赛”正式启动.美团CTO罗道峰.创新工场CEO李开复.搜狗CEO王小川和美图CEO吴欣鸿共 ...