Bibliotecas de clases portables (PCL)

Sugerencia

Las bibliotecas de clases portables (PCL) se consideran en desuso en las versiones más recientes de Visual Studio. Aunque todavía se pueden abrir, editar y compilar PCL, para los nuevos proyectos, se recomienda usar bibliotecas de .NET Standard para acceder a un área expuesta de API más grande.

Un componente clave de la creación de aplicaciones multiplataforma es poder compartir código en varios proyectos específicos de la plataforma. Sin embargo, esto es complicado por el hecho de que las distintas plataformas suelen usar un subconsulta diferente de la biblioteca de clases base (BCL) de .NET y, por lo tanto, se compilan en un perfil de biblioteca de .NET Core diferente. Esto significa que cada plataforma solo puede usar bibliotecas de clases destinadas al mismo perfil para que parezcan requerir proyectos de biblioteca de clases independientes para cada plataforma.

Hay tres enfoques principales para compartir código que abordan este problema: proyectos de .NET Standard, proyectos de recursos compartidos y proyectos de biblioteca de clases portable (PCL).

  • Los proyectos de .NET Standard son el enfoque preferido para compartir código .NET. Obtenga más información sobre los proyectos de .NET Standard y Xamarin.
  • Los proyectos de recursos compartidos usan un único conjunto de archivos y ofrecen una manera rápida y sencilla de compartir código dentro de una solución y, por lo general, emplean directivas de compilación condicionales para especificar rutas de acceso del código para las distintas plataformas que lo utilizarán (para obtener más información, consulte el artículo Proyectos compartidos).
  • Los proyectos de PCL tienen como destino perfiles específicos que admiten un conjunto conocido de clases o características de BCL. Sin embargo, el lado negativo de la PCL es que a menudo requieren esfuerzo de diseño adicional para separar el código específico del perfil en sus propias bibliotecas.

En esta página se explica cómo crear un proyecto PCL destinado a un perfil específico, al que se puede hacer referencia mediante varios proyectos específicos de la plataforma.

¿Qué es una biblioteca de clases portable?

Al crear un proyecto de aplicación o un proyecto de biblioteca, el archivo DLL resultante está restringido a trabajar en la plataforma específica para la que se crea. Esto evita que se escriba un ensamblado para una aplicación de Windows y, a continuación, se vuelva a usarlo en Xamarin.iOS y Xamarin.Android.

Sin embargo, al crear una biblioteca de clases portable, puede elegir una combinación de plataformas en las que desea que se ejecute el código. Las opciones de compatibilidad que realice al crear una biblioteca de clases portable se traducen en un identificador de "Perfil", que describe qué plataformas admite la biblioteca.

En la tabla siguiente se muestran algunas de las características que varían según la plataforma .NET. Para escribir un ensamblado PCL que se garantiza que se ejecute en dispositivos o plataformas específicos, simplemente elija qué compatibilidad es necesaria al crear el proyecto.

Característica .NET Framework Aplicaciones para UWP Silverlight Windows Phone Xamarin
Core Y Y Y Y Y
LINQ Y Y Y Y Y
IQueryable Y Y Y 7.5 (o posterior) Y
Serialización Y Y Y Y Y
Anotaciones de datos 4.0.3 + Y Y Y

La columna Xamarin refleja el hecho de que Xamarin.iOS y Xamarin.Android admiten todos los perfiles enviados con Visual Studio y la disponibilidad de características en las bibliotecas que cree solo estará limitada por las demás plataformas que elija admitir.

Esto incluye perfiles que son combinaciones de:

  • .NET 4 o .NET 4.5
  • Silverlight 5
  • Windows Phone 8
  • Aplicaciones para UWP

Puede obtener más información sobre las distintas funcionalidades de perfiles en el sitio web de Microsoft y ver el resumen de perfil de PCL de otro miembro de la comunidad, que incluye información de marco compatible y otras notas.

Ventajas

  1. Uso compartido de código centralizado: escriba y pruebe el código en un solo proyecto que otras bibliotecas o aplicaciones pueden consumir.
  2. Las operaciones de refactorización afectarán a todo el código cargado en la solución (la biblioteca de clases portable y los proyectos específicos de la plataforma).
  3. Otros proyectos pueden hacer referencia fácilmente al proyecto de PCL de una solución o el ensamblado de salida se puede compartir para que otros usuarios hagan referencia en sus soluciones.

Desventajas

  1. Dado que la misma biblioteca de clases portable se comparte entre varias aplicaciones, no se puede hacer referencia a bibliotecas específicas de la plataforma (por ejemplo, Community.CsharpSqlite.WP7).
  2. Es posible que el subconjunto de biblioteca de clases portable no incluya clases que, de lo contrario, estarían disponibles en MonoTouch y Mono para Android (como DllImport o System.IO.File).

Nota:

Las bibliotecas de clases portables han quedado en desuso en la versión más reciente de Visual Studio y se recomiendan en su lugar las bibliotecas de .NET Standard.

En cierta medida, ambas desventajas se pueden eludir mediante el patrón de proveedor o la inserción de dependencias para codificar la implementación real en los proyectos de la plataforma en una interfaz o clase base que se define en la biblioteca de clases portable.

En este diagrama se muestra la arquitectura de una aplicación multiplataforma mediante una biblioteca de clases portable para compartir código, pero también mediante la inserción de dependencias para pasar características dependientes de la plataforma:

En este diagrama se muestra la arquitectura de una aplicación multiplataforma mediante una biblioteca de clases portable para compartir código, pero también mediante la inserción de dependencias para pasar características dependientes de la plataforma

Tutorial de Visual Studio para Mac

En esta sección se explica cómo crear y usar una biblioteca de clases portable mediante Visual Studio para Mac. Consulte la sección Ejemplo de PCL para obtener una implementación completa.

Creación de una PCL

Agregar una biblioteca de clases portable a la solución es muy similar a agregar un proyecto de biblioteca normal.

  1. En el cuadro de diálogo Nuevo proyecto seleccione la opción Multiplataforma > Biblioteca > Biblioteca portable:

    Crear un nuevo proyecto de PCL

  2. Cuando se crea una PCL en Visual Studio para Mac se configura automáticamente con un perfil que funciona para Xamarin.iOS y Xamarin.Android. El proyecto de PCL aparecerá como se muestra en esta captura de pantalla:

    Proyecto PCL en el panel de solución

La PCL ya está lista para agregar código. También se puede referenciar por otros proyectos (proyectos de aplicación, proyectos de biblioteca e incluso otros proyectos PCL).

Edición de la configuración de PCL

Para ver y cambiar la configuración de PCL de este proyecto, haga clic con el botón derecho en el proyecto y elija Opciones > Compilar > General para ver la pantalla que se muestra aquí:

Opciones del proyecto de PCL para establecer el perfil

Haga clic en Cambiar... para modificar el perfil de destino de esta biblioteca de clases portable.

Si el perfil se cambia después de que el código ya se haya agregado a la PCL, es posible que la biblioteca ya no se compile si el código hace referencia a características que no forman parte del perfil recién seleccionado.

Trabajo con una PCL

Cuando el código se escribe en una biblioteca PCL, el editor de Visual Studio para Mac reconocerá las limitaciones del perfil seleccionado y ajustará las opciones de autocompletar según corresponda. Por ejemplo, esta captura de pantalla muestra las opciones de autocompletar para System.IO con el perfil predeterminado (Profile136) usado en Visual Studio para Mac: observe que la barra de desplazamiento que indica aproximadamente la mitad de las clases disponibles se muestran (de hecho, solo hay 14 clases disponibles).

Lista de IntelliSense de 14 clases en la clase System.IO de PCL

Compárelo con el autocompletar de System.IO en un proyecto de Xamarin.iOS o Xamarin.Android: hay 40 clases disponibles, incluidas clases usadas habitualmente como File y Directory que no están en ningún perfil de PCL.

Lista de IntelliSense de 40 clases en el espacio de nombres de .NET Framework System.IO

Esto refleja el equilibrio subyacente del uso de PCL: la capacidad de compartir código sin problemas entre muchas plataformas significa que ciertas API no están disponibles para usted porque no tienen implementaciones comparables en todas las plataformas posibles.

Uso de PCL

Una vez que se ha creado un proyecto PCL, puede agregar una referencia a él desde cualquier proyecto de aplicación o biblioteca compatible de la misma manera que normalmente agrega referencias. En Visual Studio para Mac, haga clic con el botón derecho en el nodo Referencias y elija Editar referencias... y cambie a la pestaña Proyectos tal como se muestra:

Agregar una referencia a una PCL mediante la opción Editar referencias

En la captura de pantalla siguiente se muestra el panel Solución de la aplicación de ejemplo TaskyPortable, que muestra la biblioteca PCL en la parte inferior y una referencia a esa biblioteca PCL en el proyecto de Xamarin.iOS.

Solución de ejemplo TaskyPortable que muestra el proyecto PCL

La salida de una PCL (es decir, el archivo DLL de ensamblado resultante) también se puede agregar como referencia a la mayoría de los proyectos. Esto hace que PCL sea una manera ideal de enviar componentes y bibliotecas multiplataforma.

Ejemplo de PCL

La aplicación de ejemplo TaskyPortable muestra cómo se puede usar una biblioteca de clases portable con Xamarin. Estas son algunas capturas de pantalla de las aplicaciones resultantes que se ejecutan en iOS y Android:

Estas son algunas capturas de pantalla de las aplicaciones resultantes que se ejecutan en iOS, Android y Windows Phone

Comparte una serie de clases de datos y lógicas que son código puramente portable y también muestra cómo incorporar requisitos específicos de la plataforma mediante la inserción de dependencias para la implementación de la base de datos de SQLite.

La estructura de la solución se muestra a continuación (en Visual Studio para Mac y Visual Studio, respectivamente):

La estructura de la solución se muestra aquí en Visual Studio para Mac y Visual Studio, respectivamente

Dado que el código de SQLite-NET tiene partes específicas de la plataforma (para trabajar con las implementaciones de SQLite en cada sistema operativo diferente) con fines de demostración, se ha refactorizado en una clase abstracta que se puede compilar en una biblioteca de clases portable y el código real implementado como subclases en los proyectos de iOS y Android.

TaskyPortableLibrary

La biblioteca de clases portable está limitada en las características de .NET que puede admitir. Dado que se compila para ejecutarse en varias plataformas, no puede usar la funcionalidad [DllImport] que se usa en SQLite-NET. En su lugar, SQLite-NET se implementa como una clase abstracta y, a continuación, se hace referencia al resto del código compartido. A continuación se muestra un extracto de la API abstracta:

public abstract class SQLiteConnection : IDisposable {

    public string DatabasePath { get; private set; }
    public bool TimeExecution { get; set; }
    public bool Trace { get; set; }
    public SQLiteConnection(string databasePath) {
         DatabasePath = databasePath;
    }
    public abstract int CreateTable<T>();
    public abstract SQLiteCommand CreateCommand(string cmdText, params object[] ps);
    public abstract int Execute(string query, params object[] args);
    public abstract List<T> Query<T>(string query, params object[] args) where T : new();
    public abstract TableQuery<T> Table<T>() where T : new();
    public abstract T Get<T>(object pk) where T : new();
    public bool IsInTransaction { get; protected set; }
    public abstract void BeginTransaction();
    public abstract void Rollback();
    public abstract void Commit();
    public abstract void RunInTransaction(Action action);
    public abstract int Insert(object obj);
    public abstract int Update(object obj);
    public abstract int Delete<T>(T obj);

    public void Dispose()
    {
        Close();
    }
    public abstract void Close();

}

El resto del código compartido usa la clase abstracta para "almacenar" y "recuperar" objetos de la base de datos. En cualquier aplicación que use esta clase abstracta, debemos pasar una implementación completa que proporcione la funcionalidad real de la base de datos.

TaskyAndroid y TaskyiOS

Los proyectos de aplicación de iOS y Android contienen la interfaz de usuario y otro código específico de la plataforma que se usa para conectar el código compartido en PCL.

Estos proyectos también contienen una implementación de la API de base de datos abstracta que funciona en esa plataforma. En iOS y Android, el motor de base de datos SQLite está integrado en el sistema operativo, por lo que la implementación puede usar [DllImport], como se muestra, para proporcionar la implementación concreta de la conectividad de la base de datos. Aquí se muestra un extracto del código de implementación específico de la plataforma:

[DllImport("sqlite3", EntryPoint = "sqlite3_open")]
public static extern Result Open(string filename, out IntPtr db);

[DllImport("sqlite3", EntryPoint = "sqlite3_close")]
public static extern Result Close(IntPtr db);

La implementación completa se puede ver en el código de ejemplo.

Resumen

En este artículo se han analizado brevemente las ventajas y problemas de las bibliotecas de clases portables, se ha mostrado cómo crear y consumir PCL desde dentro de Visual Studio para Mac y Visual Studio; y finalmente se introdujo una aplicación de ejemplo completa, TaskyPortable, que muestra una PCL en acción.