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:
If you add Xbox into the mix you will get something like this:
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:
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.
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.