可移植类库 (PCL)

提示

Visual Studio 的最新版本中, (Pcl) 的可移植类库被视为已弃用。 尽管仍可以打开、编辑和编译 Pcl,但对于新项目,建议使用 .NET Standard 库 来访问更大的 API 外围应用。

构建跨平台应用程序的一个关键组件是能够跨不同于平台的项目共享代码。 但是,这种情况很复杂,这是因为不同的平台通常使用不同的 .NET 基类库子集 (BCL) ,因此实际构建到不同的 .NET Core 库配置文件中。 这意味着,每个平台只能使用以相同配置文件为目标的类库,因此它们似乎需要为每个平台使用单独的类库项目。

有三种主要的代码共享方法可解决此问题: .NET Standard 项目共享资产项目可移植类库 (PCL) 项目

  • .NET Standard 项目 是用于共享 .net 代码的首选方法,请阅读有关 .NET Standard 项目和 Xamarin的详细信息。
  • 共享资产项目 使用一组文件,并提供一种快速而简单的方法,用于在解决方案中共享代码,通常使用条件编译指令来指定将使用它 (的各种平台的代码路径。有关详细信息,请参阅 共享项目一文) 。
  • PCL 项目面向支持一组已知的 BCL 类/功能的特定配置文件。 但是,PCL 的向下,它们通常需要额外的体系结构,以便将配置文件特定代码分隔到它们自己的库中。

本页说明如何创建以特定配置文件为目标的 PCL 项目,该配置文件随后可由多个特定于平台的项目引用。

什么是可移植类库?

Project 或库 Project 创建应用程序时,所生成的 DLL 将被限制为可以在为其创建该应用程序的特定平台上工作。 这会阻止你为 Windows 应用编写程序集,然后在 xamarin 和 xamarin 上重新使用该程序集。

但是,在创建可移植类库时,可以选择想要在其中运行代码的平台组合。 创建可移植类库时所做的兼容性选择会转换为 "Profile" 标识符,该标识符描述库支持哪些平台。

下表显示了由 .NET 平台变化的一些功能。 若要编写保证在特定设备/平台上运行的 PCL 程序集,只需选择创建项目时所需的支持。

功能 .NET Framework UWP 应用 Silverlight Windows Phone Xamarin
核心 Y Y Y Y Y
LINQ Y Y Y Y Y
IQueryable Y Y Y 7.5 + Y
序列化 Y Y Y Y Y
数据注释 4.0.3 + Y Y Y

xamarin 列反映的事实是,xamarin 和 xamarin 支持 Visual Studio 附带的所有配置文件,你创建的任何库中的功能可用性仅受你选择支持的其他平台的限制。

这包括组合的配置文件:

  • .NET 4 或 .NET 4。5
  • Silverlight 5
  • Windows Phone 8
  • UWP 应用

可以在 Microsoft 网站 上阅读有关不同配置文件功能的详细信息,并查看另一个社区成员的 PCL 配置文件摘要 ,其中包括受支持的框架信息和其他说明。

优点

  1. 集中式代码共享–在可由其他库或应用程序使用的单个项目中编写和测试代码。
  2. 重构操作将影响解决方案中加载的所有代码 (可移植类库和) 平台特定的项目。
  3. 解决方案中的其他项目可以轻松地引用 PCL 项目,或者可以共享输出程序集以便其他人在其解决方案中引用。

缺点

  1. 因为在多个应用程序之间共享相同的可移植类库,所以不能引用特定于平台的库 (例如。 Community。CsharpSqlite. WP7) 。
  2. 可移植类库子集不能包含在 Monotouch.dialog 和 Mono for Android (如 DllImport 或) 中都可用的类。

备注

可移植类库在最新版本的 Visual Studio 中已弃用,建议改为使用.NET Standard 库

在某种程度上,可以使用提供程序模式或依赖项注入对平台项目中的实际实现进行编码,以便对可移植类库中定义的接口或基类进行编码。

此图显示了使用可移植类库共享代码的跨平台应用程序的体系结构,但也使用依赖关系注入来传递依赖于平台的功能:

此图显示了使用可移植类库共享代码的跨平台应用程序的体系结构,还使用依赖关系注入来传入依赖于平台的功能

Visual Studio for Mac 演练

本部分介绍如何使用 Visual Studio for Mac 创建和使用可移植类库。 有关完整实现,请参考 PCL 示例部分。

创建 PCL

向解决方案添加可移植类库与添加常规库项目非常相似。

  1. 在 "新建 Project " 对话框中,选择 "多 平台" > 库 > 可移植库"选项:

    创建新的 PCL 项目

  2. 当在中创建 PCL 时 Visual Studio for Mac 它会自动配置一个适用于 Xamarin 和 xamarin 的配置文件。 此时将显示 PCL 项目,如以下屏幕截图所示:

    解决方案板中的 PCL 项目

PCL 现在已准备好添加代码。 它还可由其他项目引用 (应用程序项目、库项目甚至) 其他 PCL 项目。

编辑 PCL 设置

若要查看和更改此项目的 PCL 设置,请右键单击该项目,然后选择 " 选项" > 生成 > 常规 "以查看此处所示的屏幕:

PCL Project 选项来设置配置文件

单击 " 更改 ... " 更改此可移植类库的目标配置文件。

如果在将代码添加到 PCL 后,配置文件发生了更改,则在代码引用了不是新选择的配置文件的一部分的功能时,库将无法再编译。

使用 PCL

在 PCL 库中编写代码时,Visual Studio for Mac 编辑器将识别所选配置文件的限制,并相应地调整自动完成选项。 例如,此屏幕截图显示了 System.IO 的自动完成选项,其中使用了 Visual Studio for Mac 中使用的默认配置文件 (Profile136) ,请注意,显示大约一半可用类的滚动条会显示 (,实际上只有14个类) 可用。

PCL 的 System.IO 类中14类的 Intellisense 列表

将其与 Xamarin 或 Xamarin 项目中的 System.IO 自动完成进行比较–提供了40类,包括常用类(如 FileDirectory ),它们不在任何 PCL 配置文件中。

.NET Framework System.IO 命名空间中40类的 Intellisense 列表

这反映了使用 PCL 的底层权衡–能够无缝地跨多个平台共享代码,这意味着某些 Api 不能供你使用,因为它们没有跨所有可能平台的可比较实现。

使用 PCL

创建 PCL 项目后,可以使用通常添加引用的方式,从任何兼容的应用程序或库项目添加对它的引用。 在Visual Studio for Mac,右键单击"引用"节点并选择"编辑引用 ...", 然后切换到"项目 " 选项卡,如下所示:

通过"编辑引用"选项添加对 PCL 的引用

以下屏幕截图显示了 TaskyPortable 示例应用的 Solution pad,其中底部显示了 PCL 库,以及 Xamarin.iOS 项目中该 PCL 库的引用。

显示 PCL 项目的 TaskyPortable 示例解决方案

PCL 输出 (输出。生成的程序集 DLL) 也可以添加为对大多数项目的引用。 这使得 PCL 成为提供跨平台组件和库的理想方式。

PCL 示例

TaskyPortable示例应用程序演示如何将可移植类库与 Xamarin 一起使用。 下面是在 iOS 和 Android 上运行的结果应用的一些屏幕截图:

下面是在 iOS、Android 和 Windows Phone 上运行的结果应用的一些屏幕截图

它共享许多纯可移植代码的数据和逻辑类,还演示了如何使用 SQLite 数据库实现的依赖关系注入来合并特定于平台的要求。

解决方案结构显示在 (和Visual Studio for Mac Visual Studio中) :

解决方案结构分别显示在 Visual Studio for Mac Visual Studio 中

由于 SQLite-NET 代码具有特定于平台的部分 (用于处理每个不同操作系统) 上的 SQLite 实现(出于演示目的)已重构为可编译为可移植类库的抽象类,以及作为 iOS 和 Android 项目中的子类实现的实际代码。

TaskyPortableLibrary

可移植类库在它可以支持的 .NET 功能中受到限制。 由于已编译为在多个平台上运行,因此无法使用 [DllImport] SQLite-NET 中使用的功能。 而是将 SQLite-NET 实现为抽象类,然后通过共享代码的其余部分进行引用。 抽象 API 的提取如下所示:

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();

}

共享代码的其余部分使用抽象类从数据库中"存储"和"检索"对象。 在使用此抽象类的任何应用程序中,我们必须传递提供实际数据库功能的完整实现。

TaskyAndroid 和 TaskyiOS

iOS 和 Android 应用程序项目包含用户界面和其他特定于平台的代码,用于连接 PCL 中的共享代码。

这些项目还包含适用于该平台的抽象数据库 API 的实现。 在 iOS 和 Android 上,Sqlite 数据库引擎内置于操作系统中,因此实现可以使用 ,如所示提供数据库连接 [DllImport] 的具体实现。 下面显示了特定于平台的实现代码的摘录:

[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);

可以在示例代码中看到完整实现。

摘要

本文简要介绍了可移植类库的好处和缺陷,演示了如何从内部创建和使用 PCL Visual Studio for Mac Visual Studio;最后引入了一个完整的示例应用程序 TaskyPortable,它演示了 PCL 的运行情况。