可移植类库 (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 项目,然后多个特定于平台的项目可以引用该项目。

什么是可移植类库?

创建应用程序项目或库项目时,生成的 DLL 仅限于在为其创建的特定平台上工作。 这会阻止你为 Windows 应用编写程序集,然后在 Xamarin.iOS 和 Xamarin.Android 上重新使用它。

但是,在创建可移植类库时,可以选择希望运行代码的平台组合。 创建可移植类库时所做的兼容性选择将转换为“配置文件”标识符,该标识符描述库支持的平台。

下表显示了一些因 .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.iOS 和 Xamarin.Android 支持 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 和 Mono for Android (中可用的类,例如 DllImport 或 System.IO.File) 。

注意

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

在一定程度上,可以使用提供程序模式或依赖关系注入来针对可移植类库中定义的接口或基类对平台项目中的实际实现进行编码,从而避免这两个缺点。

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

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

Visual Studio for Mac演练

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

创建 PCL

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

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

    创建新的 PCL 项目

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

    解决方案板中的 PCL 项目

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

编辑 PCL 设置

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

用于设置配置文件的 PCL 项目选项

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

如果在代码已添加到 PCL 后更改配置文件,则如果代码引用的功能不属于新选择的配置文件,则库可能不再编译。

使用 PCL

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

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

与 Xamarin.iOS 或 Xamarin.Android 项目中的自动完成 System.IO 比较 - 有 40 个可用类,包括任何 PCL 配置文件中未包含的常用类(如 FileDirectory )。

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

这反映了使用 PCL 的基本权衡 – 跨多个平台无缝共享代码的能力意味着某些 API 不可用,因为它们在所有可能的平台中没有类似的实现。

使用 PCL

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

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

以下屏幕截图显示了 TaskyPortable 示例应用的解决方案板,底部显示了 PCL 库,以及 Xamarin.iOS 项目中该 PCL 库的引用。

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

PCL (ie 的输出。生成的程序集 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);

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

总结

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