Thursday, August 29, 2013

PCL libraries overview

This is very good article on the PCL architecture and different ways to implement a PCL library:
http://blogs.msdn.com/b/dsplaisted/archive/2012/08/27/how-to-make-portable-class-libraries-work-for-you.aspx
Important quote:
“The code to use your library should also be simple.  That means the project referencing your library shouldn’t have to manage hooking up the platform specific part of your library with the portable part.  One way to do this is to have an initialize method in your platform specific part of your library which passes references to platform specific implementations down to the portable part of your library.  Here’s an example of what this could look like"
“For consumers of your library, it will be easier if the portable part of your library connects to the platform specific part with no action required on their part.  You can do this by having the portable part load the platform-specific part by calling Assembly.Load(), and using reflection to get the functionality it needs.  For an example of how to do this, see  the Portable Class Libraries Contrib project.  The code which handles this functionality is in the Source\Portable.Runtime\Adaptation folder.  The Reactive Extensions (Rx) also use this method to connect their portable System.Reactive.Core assembly with the platform-specific System.Reactive.PlatformServices assembly. “
A simple example of PCL is PCL Storage: http://pclstorage.codeplex.com/
The project consists of a PCL project (platform independent) called PCLStorage.Abstractions and specific platform projects called PCLStorage.[PlatformName]
image
PCLStorage.Abstractions is referenced by all platform implementation projects (the PCLStorage.[PlatformName] projects).
It contains definitions of interfaces which platform implementations implement.
image
namespace PCLStorage
{
    public static class FileSystem
    {
        public static IFileSystem Current { get; }
    }

    public interface IFileSystem
    {
        IFolder LocalStorage { get; }
        IFolder RoamingStorage { get; }

        Task<IFile> GetFileFromPathAsync(string path);
        Task<IFolder> GetFolderFromPathAsync(string path);
    }

    public enum CreationCollisionOption
    {
        GenerateUniqueName = 0,
        ReplaceExisting = 1,
        FailIfExists = 2,
        OpenIfExists = 3,
    }

    public interface IFolder
    {
        string Name { get; }
        string Path { get; }

        Task<IFile> CreateFileAsync(string desiredName, CreationCollisionOption option);
        Task<IFile> GetFileAsync(string name);
        Task<IList<IFile>> GetFilesAsync();

        Task<IFolder> CreateFolderAsync(string desiredName,
            CreationCollisionOption option);
        Task<IFolder> GetFolderAsync(string name);
        Task<IList<IFolder>> GetFoldersAsync();

        Task DeleteAsync();
    }

    public enum FileAccess
    {
        Read,
        ReadAndWrite
    }

    public interface IFile
    {
        string Name { get; }
        string Path { get; }

        Task<Stream> OpenAsync(FileAccess fileAccess);
        Task DeleteAsync();
    }

    public static class PortablePath
    {
        public static char DirectorySeparatorChar { get; }
        public static string Combine(params string[] paths);
    }
    public static class FileExtensions
    {
        public static async Task<string> ReadAllTextAsync(this IFile file)
        public static async Task WriteAllTextAsync(this IFile file, string contents);
    }
}



So when developer installs PCLStorage from NuGet for a specific project on a specific platofrm, NuGet manager will add as reference to the project the PCLStorage.Abstractions.dll PCL and the PCLStorage.[PlatformName].dll implementation.

In code, here’s how PCLStorage library is used:


public async Task PCLStorageSample()
{
    IFolder rootFolder = FileSystem.Current.LocalStorage;
    IFolder folder = await rootFolder.CreateFolderAsync("MySubFolder",
        CreationCollisionOption.OpenIfExists);
    IFile file = await folder.CreateFileAsync("answer.txt",
        CreationCollisionOption.ReplaceExisting);
    await file.WriteAllTextAsync("42");
}

FileSystem.Current is instantiating the platform specific IFileSystem.

This code resides in a file in PCLStorage.dll PCL which is linked to other PCLStorage.[PlatfortmName].dll projects

PCLStorage.dll is not used besides just for holding files to be linked (it is not used as reference by any projects)

No comments: