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/

时间: 2024-11-06 07:34:32

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 multiple .NET platforms.  When you create a Portable Class Library in Visual Studio, you can choose which platforms to target.  Portable libraries su

[译]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 initiative, ASP.NET MVC 6 represents a fundamental change to how Microsoft constructs and deploys web frameworks. The goal is to create a host agnostic fr

The .NET of Tomorrow

Ed Charbeneau(http://developer.telerik.com/featured/the-net-of-tomorrow/) Exciting times lie ahead for .NET developers. During Build, Microsoft’s biggest developer event of the year, clear roadmaps were given on the future of .NET and C#. Microsoft i

.NET 开源开发项目

本文列出了 .NET 开源开发项目(open source developer projects).意在包括对开发过程的所有方面有所帮组的项目.对于消费项目(consumerprojects),请参阅.NET开源消费项目清单. 下面按字母排序,并提供一行文字说明.GitHub/CodePlex(或其他)链接优先. .NET 实现 .NET Core - Core .NET 框架 C# Native – 把 C# 编译成本地代码. Cosmos - C# 开源的管理操作系统,一个操作系统是"con

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=tuicool NET Implementations .NET Core – Core .NET Framework C# Native – Compiles C# to native. Cosmos – C# Open Source Managed Operating System, an operat

[转载] boost thread用法

原文: http://antonym.org/2009/05/threading-with-boost---part-i-creating-threads.html boost库中thread的用法官方文档写的不是特别清楚, 这篇文章给出了比较清晰的介绍和例子. Threading with Boost - Part I: Creating Threads May 13, 2009 Boost is an incredibly powerful collection of portable cl

.NET 开源开发项目【翻译】

原文地址 本文列出了 .NET 开源开发项目(open source developer projects).意在包括对开发过程的所有方面有所帮组的项目.对于消费项目(consumer projects),请参阅 .NET开源消费项目清单. 下面按字母排序,并提供一行文字说明.GitHub/CodePlex(或其他)链接优先. .NET 实现 .NET Core - Core .NET 框架 C# Native – 把 C# 编译成本地代码. Cosmos - C# 开源的管理操作系统,一个操作

问题:IIS部署 MVC项目 (autofac) 错误解决

http://www.cnblogs.com/yelaiju/p/3375168.html Could not load file or assembly 'System.Core, Version=2.0.5.0 和autofac冲突的问题 在部署到iis的时候会出现这个状况. 解决:下载安装这个补丁 http://support.microsoft.com/kb/2468871 http://www.microsoft.com/zh-cn/download/confirmation.aspx

centos7下源码编译方式安装httpd

语法: chkconfig --list [name] chkconfig --add name chkconfig --del name chkconfig [--level levels] name <on|off|reset> chkconfig [--level levels] name 参考文章http://www.cnblogs.com/jipeng87/p/6308725.html 前言 Apache至少需要apr.apr-util.pcre组件的支持. APR(Apache p