I have a long-standing interest in portable class libraries (PCL), because most of my open-source contributions are widely-applicable libraries (including Comparers, ArraySegments, and of course AsyncEx). This post is an explanation of a technique that I learned from Rx; it's useful for any PCL that is actually a library (i.e., not a portable application).
Portable class libraries are awesome. Now that NuGet supports them, every library writer should join in!
Portable Class Libraries enable you to create a single binary that runs on several (.NET) platforms. Unfortunately, it uses the "least common denominator" approach, which means your PCL is greatly constrained in what it can do. In order to "step outside" these restrictions, you need some way for a platform-specific assembly to provide functionality to your PCL core. The obvious answer is to use inversion of control, but how are the (platform-specific) implementations created and passed to your portable code?
There are several ways to do this. Daniel Plaisted has a great blog post that gives an overview of different solutions:
- Manual dependency injection (passing interface implementations into constructors). Daniel's classic "Disentaglement" demo uses this approach as he describes in his //build/ talk. This is OK if your PCL just has a few large classes (e.g., ViewModels) which are always the "entry point" to your PCL. It's not so good if your PCL is more of a generic library.
- Real dependency injection. The disadvantage to this approach is that it restricts all users of a PCL to a specific DI provider.
- Service locator (static variables holding the interface implementations). This approach is described in the official MSDN documentation (section "Platform Abstraction"). This requires all code using the PCL to "wire up" its own implementations.
- Platform enlightenment / adaptation libraries (extra assemblies loaded via reflection). This is the approach described in this blog post.
The first three approaches depend on the consumer of the library implementing the platform services (or at least instantiating them) and providing them to the portable library:
This is fine if your PCL is just the core of a portable application, like Daniel's "Disentanglement" application, where the PCL contains the logic but its "entry points" are just a handful of ViewModels.
But I'm not a fan of this. When I distribute a library, I want users to just add it via NuGet and start using it; requiring "startup" code is a big barrier to adoption.
AFAIK, the Rx team was the first to solve this problem. They describe their "Platform Enlightenment" approach well on their blog (section "Intermezzo - The refactored API surface"). Members of the PCL team have referred to this technique as "Platform Adaptation".
I was just chatting with someone today at work about PCL and how you can use them to re-use binaries...
Related Past Post XRef:
Need a refresher on what Portable Class Library Projects are? (For your co-workers of course, since YOU know about them already... right?)
GoTo Portable Class Libraries - Now's the time to start using them as your default Class Project template?
It's RX v2 Baby! Reactive Extensions v2.0 RTW, with details, download and the SDK too!
Update 4.0.3 for Microsoft .NET Framework 4 Roundup
Visual Studio 2010 is now ever more portable (No, not that kind of portable)... As in the release of the Portable Library Tools 2 Beta for Visual Studio 2010
Using the Portable Library Tools, a tutorial
Portable Library Tools RTW (think "One library binary, many platforms")
Write (.Net library) once, use everywhere (in .Net world)? The Portable Library Tools CTP Released. (Think “Reusing/Sharing the same Project between SilverLight, XNA, Windows Phone, etc” or “DRY .Net Project Style” )