Portable class libraries or source code sharing?

Earlier I wrote a blog post on a specific method to implement code sharing between Windows Store and Windows Phone applications.

In this post I want to zoom out a little bit and look at the different techniques available and explain what the differences and advantages are. That way you can employ these techniques in the correct situation.

There are basically two techniques:

  • Portable class libraries
  • Source code sharing

Portable class libraries

The preferred way to reuse code is using portable class libraries. This is because you are sharing on the binary level and that’s how we normally reuse code. It’s in the form of a class library and we reuse the DLL.
However, there are some problems and limitations in reusing portable class libraries:

  • You can only share code. Since it’s a class library you cannot share xaml for example. (Although I wouldn’t recommend this, as the UI is very different for Phone and Windows 8)
  • References to other libraries: If you have dependencies on other components or NuGet packages (MVVM Light for example)  in your main application assembly and you need to access these in the PCL, you need a PCL version of that component. In some cases these packages are not available. A very important thing to remember if you develop for multiple platforms: Always make sure you install the PCL version of an external component or package. In NuGet these are usually marked with “PCL”. (Note: Make sure you have NuGet 2.2 installed in order to have support for PCL packages).
  • You get a subset of the framework, more accurately, you get the common denominator between the frameworks you are targeting. So, for example, if you target Windows Phone and Windows 8, you get the following:
    Shared code in Windows 8 and Windows Phone

    If you add Xbox into the mix you will get something like this:

     image

    As you can see, the more frameworks you target, the smaller the API gets. In order to circumvent this problem you can declare your interfaces in the PCL, talk to these interfaces and then implement the API specific things in separate libraries targeted specifically towards these APIs. You can check out my other post on sharing code between platforms for more information on that.
    The table beneath gives an overview of what’s supported in PCL’s:

     
     

    Feature

    .NET Framework

    Windows Store

    Silverlight

    Windows Phone

    Xbox 360

    Core BCL Yes Yes Yes Yes Yes
    Core XML Yes Yes Yes Yes Yes
    Core WCF Yes Yes Yes Yes  
    Core networking Yes Yes Yes Yes  
    XML Serialization Yes Yes Yes Yes  
    JSON serialization Yes Yes Yes Yes  
    Datacontract serialization Yes Yes Yes Yes  
    IQueryable Yes Yes Yes 7.5 and higher  
    dynamic keyword 4.5 Yes Yes    
    View Models 4.5 Yes Yes Yes  
    Data Annotations 4.03 and up Yes Yes Yes  
    LINQ Yes Yes Yes Yes  
    XLINQ 4.0.3 and up Yes Yes Yes Yes
    MEF Yes Yes Yes    
    System.Numerics Yes Yes Yes    

    The biggest limitation in PCL’s you’ll run into is when accessing platform specific API’s such as tile updates, isolated storage and application settings.

Source code sharing

Another form of reuse is through linked source code. What we’re effectively doing is linking on the source code level instead of at the binary level. In order to do this you have to add an existing item as a link.

add_item_as_link

This will add the file to your project, but the actual file still lives inside the directory of the source project. If you update it, it will update in both libraries. I’d recommend portable class libraries over this technique in most cases. The reason for that is that code can get quite messy with linked source files.

  • You are still limited to the common API. Since the source file has to work in multiple projects, you still have to make sure you only target what will work in both environments. However, there’s one technique that you can use to circumvent this: Preprocessing directives. Just like you can test for debug mode, you can do the following:
        // do common operations
    #if WINDOWS_PHONE
        // do phone related things
    #elif NETFX_CORE
        // do win 8 things
    #endif
    

    In your shared code file you can use these directives to target the different platforms. At compile time, the compiler will only include the code for that platform. If you look at the Build-tab of your project’s properties, you’ll notice that these preprocessing directives are already defined. Off course, you could add your own as well.
    Beware though, you should only do this if you have very few of these, otherwise your code could become sprinkled with these statements, and it makes everything less readable.

  • You could accidently introduce incompatible code. While writing your code in a shared source code file from within a project, the tools will consider the file a part of the project you opened it from. This affects both intellisense and the compiler. So when compiling the project the compiler will only check the file for that platform. If both projects are only maintained by the same person the risk can be mitigated because you are aware of the linked file. Things can get quite complicated though if multiple people work on different projects, sharing source files.

When to use what?

In general I’d recommend using portable class libraries, since it’s binary reuse. However in the following cases it might be useful to share code files:

  • You want to share some XAML (for example, some small data templates or resources)
  • Your code is exactly the same on both platforms, but the PCL doesn’t support it. This happens sometimes when both API’s live in different namespaces.
  • You have an inseparable unit that’s only different in a small part. You can use preprocessor directives to overcome this.
  • Pingback: Portable class libraries or source code linking?

  • http://www.facebook.com/profile.php?id=572644060 Simon Jackson

    Both solutions as you say have their use cases and in some a mix of both solutions is required.

    But I always recommend to keep as much code in a central portable class library as possible and if adding a single platform (such as XBOX) restricts too much then consider a separate deployable for just that platform. Better to have 90% share across 3 or more projects than limit to 20% on all.

    Code that doesn’t fit, such as XAML do need to be either platform specific or if they can be shared then in a Linked CS file and use #if statements to make it buildable per platform.

    Great article!

  • http://blog.mrlacey.co.uk/ Matt Lacey

    I particularly like to use linked files when I’m using partial classes and partial methods to have slightly different or extended behaviour on different platforms. I find it much easier to keep track of classes that are split across multiple files when I can keep the file references together in a project.

  • http://www.facebook.com/profile.php?id=532237612 Simon Ferquel

    I can’t understand the hipe around “Portable Class Library”. They are very restrictive in many ways, and from a developer point of view (not for an architect, build manager or other non-coding persona), it provides far less portable code sharing opportunities than file links. (for example on some platforms same class are in different namespaces but have the same public signature and provide significant sets of common functionality. Within portable libraries, I cannot use them).

    If you want a very good example of big multi-platform projects, just take a look at the various C++ game engines out there. They all rely on code file links and pre-processor directives.

  • Kenneth Truyers

    @SimonJackson: I haven’t developed for XBox yet, but looking at the table I reckon it will probably render the PCL almost useless. I guess the only thing you could share would be DTO’s and some utility classes. Then again, the platforms are very different.

    @MattLacey: Excellent point. I have actually used this technique before. It would be a good addition to the article.

    @SimonFerquel: My problem with linked files is that I feel like I constantly have to split my mind, thinking about both platforms at the same time. You are right that in cases where classes have the same signature but live in different namespaces it’s better to use linked files. On the other hand, I would like to see Microsoft do something about that and extend the power of PCL’s, which is the road I think they will be taking with the next releases.

  • http://www.facebook.com/profile.php?id=2214354 Jeff Wilcox

    I’m with Matt here, but about to consider trying the Portable Class Library route for some new work now that there’s prerelease versions of both the BCL async libraries and BCL team’s HttpClient that work with PCLs. Maybe over time PCL will get more attractive… if nothing else I’m getting super tired of adding files as links and using #ifdefs.

    Nice post.

    • Kenneth Truyers

      Hello Jeff,

      At the moment I still use a mixture of both, exactly because in some aspects PCL’s are rather limited. But I think the general direction MS is heading is to put more and more functionality into the PCL’s and have truly cross platform code (as long as those platforms are from the Microsoft stack of course :-) )

      The #ifdef statements just seem very clunky to me and I like to avoid them as much as possible, but unfortunately sometimes you have no other choice. Although I find that with using interfaces you can abstract a lot of the specifics away.