Portable Klassenbibliotheken

Tipp

Portable Klassenbibliotheken (PCLs) gelten in den neuesten Versionen von Visual Studio als veraltet. Sie können weiterhin PCLs öffnen, bearbeiten und kompilieren, aber für neue Projekte wird empfohlen , .NET Standard-Bibliotheken zu verwenden, um auf eine größere API-Oberfläche zuzugreifen.

Eine wichtige Komponente beim Erstellen plattformübergreifender Anwendungen ist die Möglichkeit, Code für verschiedene plattformspezifische Projekte freizugeben. Dies wird jedoch durch die Tatsache erschwert, dass verschiedene Plattformen häufig eine andere Untermenge der .NET Base Class Library (BCL) verwenden und daher tatsächlich für ein anderes .NET Core-Bibliotheksprofil erstellt werden. Dies bedeutet, dass jede Plattform nur Klassenbibliotheken verwenden kann, die auf dasselbe Profil ausgerichtet sind, sodass sie anscheinend separate Klassenbibliotheksprojekte für jede Plattform erfordern.

Es gibt drei Hauptansätze für die Codefreigabe, die dieses Problem beheben: Projekte mit .NET Standard, Projekte für gemeinsame Ressourcen und PCL-Projekte (Portable Class Library).

  • .NET Standard-Projekte sind der bevorzugte Ansatz für die Freigabe von .NET-Code. Weitere Informationen finden Sie unter .NET Standard-Projekte und Xamarin.
  • Shared Asset Projects verwenden einen einzelnen Satz von Dateien und bieten eine schnelle und einfache Möglichkeit zum Freigeben von Code in einer Projektmappe und verwenden im Allgemeinen Anweisungen zur bedingten Kompilierung, um Codepfade für verschiedene Plattformen anzugeben, die ihn verwenden werden (weitere Informationen finden Sie im Artikel Freigegebene Projekte).
  • PCL-Projekte zielen auf bestimmte Profile ab, die einen bekannten Satz von BCL-Klassen/Features unterstützen. Der Nachteil von PCL ist jedoch, dass sie häufig zusätzlichen architektonischen Aufwand erfordern, um profilspezifischen Code in ihre eigenen Bibliotheken zu trennen.

Auf dieser Seite wird erläutert, wie Sie ein PCL-Projekt erstellen, das auf ein bestimmtes Profil abzielt, auf das dann mehrere plattformspezifische Projekte verweisen können.

Was ist eine portable Klassenbibliothek?

Wenn Sie ein Anwendungsprojekt oder ein Bibliotheksprojekt erstellen, ist die resultierende DLL auf die Arbeit auf der spezifischen Plattform beschränkt, für die sie erstellt wird. Dadurch wird verhindert, dass Sie eine Assembly für eine Windows-App schreiben und diese dann unter Xamarin.iOS und Xamarin.Android erneut verwenden.

Beim Erstellen einer portablen Klassenbibliothek können Sie jedoch eine Kombination von Plattformen auswählen, auf denen Ihr Code ausgeführt werden soll. Die Kompatibilitätsoptionen, die Sie beim Erstellen einer portablen Klassenbibliothek treffen, werden in einen Bezeichner "Profil" übersetzt, der beschreibt, welche Plattformen von der Bibliothek unterstützt werden.

Die folgende Tabelle zeigt einige der Features, die je nach .NET-Plattform variieren. Um eine PCL-Assembly zu schreiben, die garantiert auf bestimmten Geräten/Plattformen ausgeführt wird, wählen Sie einfach aus, welche Unterstützung beim Erstellen des Projekts erforderlich ist.

Funktion .NET Framework UWP-Apps Silverlight Windows Phone Xamarin
Core J J J J J
LINQ J J J J J
IQueryable J J J 7.5 + J
Serialisierung J J J J J
Datenanmerkungen 4.0.3 + J J J

Die Xamarin-Spalte spiegelt die Tatsache wider, dass Xamarin.iOS und Xamarin.Android alle mit Visual Studio gelieferten Profile unterstützen, und die Verfügbarkeit von Features in allen bibliotheken, die Sie erstellen, wird nur durch die anderen Plattformen eingeschränkt, die Sie unterstützen.

Dies umfasst Profile, die kombinationen aus:

  • .NET 4 oder .NET 4.5
  • Silverlight 5
  • Windows Phone 8
  • UWP-Apps

Weitere Informationen zu den Funktionen der verschiedenen Profile finden Sie auf der Microsoft-Website und in der PCL-Profilzusammenfassung eines anderen Communitymitglieds, die unterstützte Frameworkinformationen und andere Hinweise enthält.

Vorteile

  1. Zentralisierte Codefreigabe: Schreiben und Testen von Code in einem einzelnen Projekt, der von anderen Bibliotheken oder Anwendungen genutzt werden kann.
  2. Umgestaltungsvorgänge wirken sich auf den gesamten Code aus, der in die Projektmappe geladen wird (die portable Klassenbibliothek und die plattformspezifischen Projekte).
  3. Auf das PCL-Projekt kann problemlos von anderen Projekten in einer Projektmappe verwiesen werden, oder die Ausgabeassembly kann für andere freigegeben werden, um in ihren Projektmappen darauf zu verweisen.

Nachteile

  1. Da dieselbe portable Klassenbibliothek von mehreren Anwendungen gemeinsam genutzt wird, kann nicht auf plattformspezifische Bibliotheken verwiesen werden (z. B. Community.CsharpSqlite.WP7).
  2. Die Teilmenge der portablen Klassenbibliothek enthält möglicherweise keine Klassen, die andernfalls sowohl in MonoTouch als auch in Mono für Android verfügbar wären (z. B. DllImport oder System.IO.File).

Hinweis

Portable Klassenbibliotheken sind in der neuesten Version von Visual Studio veraltet, und stattdessen werden .NET-Standardbibliotheken empfohlen.

Bis zu einem gewissen Grad können beide Nachteile mithilfe des Anbietermusters oder der Abhängigkeitsinjektion umgangen werden, um die tatsächliche Implementierung in den Plattformprojekten für eine Schnittstelle oder Basisklasse zu codieren, die in der portablen Klassenbibliothek definiert ist.

Dieses Diagramm zeigt die Architektur einer plattformübergreifenden Anwendung, die eine portable Klassenbibliothek zum Freigeben von Code verwendet, aber auch die Verwendung von Abhängigkeitsinjektion zum Übergeben plattformabhängiger Features:

Dieses Diagramm zeigt die Architektur einer plattformübergreifenden Anwendung, die eine portable Klassenbibliothek zum Freigeben von Code verwendet, aber auch die Verwendung von Abhängigkeitsinjektion zum Übergeben plattformabhängiger Features

Visual Studio für Mac exemplarische Vorgehensweise

In diesem Abschnitt wird beschrieben, wie Sie eine portable Klassenbibliothek mit Visual Studio für Mac erstellen und verwenden. Eine vollständige Implementierung finden Sie im Abschnitt PCL-Beispiel.

Erstellen einer PCL

Das Hinzufügen einer portablen Klassenbibliothek zu Ihrer Projektmappe ähnelt dem Hinzufügen eines regulären Bibliotheksprojekts.

  1. Wählen Sie im Dialogfeld Neues Projekt die Option Portable Bibliothek für mehrere Plattformen >> aus:

    Erstellen eines neuen PCL-Projekts

  2. Wenn eine PCL in Visual Studio für Mac erstellt wird, wird sie automatisch mit einem Profil konfiguriert, das für Xamarin.iOS und Xamarin.Android funktioniert. Das PCL-Projekt wird wie in diesem Screenshot dargestellt angezeigt:

    PCL-Projekt im Projektmappenpad

Die PCL ist jetzt bereit für das Hinzufügen von Code. Es kann auch von anderen Projekten (Anwendungsprojekte, Bibliotheksprojekte und sogar andere PCL-Projekte) darauf verwiesen werden.

Bearbeiten von PCL-Einstellungen

Um die PCL-Einstellungen für dieses Projekt anzuzeigen und zu ändern, klicken Sie mit der rechten Maustaste auf das Projekt, und wählen Sie Optionen > Erstellen > Allgemein aus, um den hier gezeigten Bildschirm anzuzeigen:

PCL-Projektoptionen zum Festlegen des Profils

Klicken Sie auf Ändern... , um das Zielprofil für diese portable Klassenbibliothek zu ändern.

Wenn das Profil geändert wird, nachdem der PCL bereits Code hinzugefügt wurde, wird die Bibliothek möglicherweise nicht mehr kompiliert, wenn der Code auf Features verweist, die nicht Teil des neu ausgewählten Profils sind.

Arbeiten mit einer PCL

Wenn Code in eine PCL-Bibliothek geschrieben wird, erkennt der Visual Studio für Mac-Editor die Einschränkungen des ausgewählten Profils und passt die Optionen für die automatische Vervollständigung entsprechend an. Dieser Screenshot zeigt beispielsweise die Autovervollständigen-Optionen für System.IO mit dem standardprofil (Profile136), das in Visual Studio für Mac verwendet wird. Beachten Sie die Bildlaufleiste, die angibt, dass etwa die Hälfte der verfügbaren Klassen angezeigt wird (tatsächlich sind nur 14 Klassen verfügbar).

Intellisense-Liste mit 14 Klassen in der System.IO-Klasse einer PCL

Vergleichen Sie dies mit dem System.IO auto-complete in einem Xamarin.iOS- oder Xamarin.Android-Projekt – es sind 40 Klassen verfügbar, darunter häufig verwendete Klassen wie File und Directory die sich in keinem PCL-Profil befinden.

Intellisense-Liste mit 40 Klassen in .NET Framework System.IO Namespace

Dies spiegelt den zugrunde liegenden Kompromiss der Verwendung von PCL wider: Die Möglichkeit, Code nahtlos über viele Plattformen hinweg freizugeben, bedeutet, dass bestimmte APIs nicht für Sie verfügbar sind, da sie nicht über vergleichbare Implementierungen auf allen möglichen Plattformen verfügen.

Verwenden von PCL

Sobald ein PCL-Projekt erstellt wurde, können Sie einen Verweis darauf aus jedem kompatiblen Anwendungs- oder Bibliotheksprojekt auf die gleiche Weise hinzufügen, wie Sie normalerweise Verweise hinzufügen. Klicken Sie in Visual Studio für Mac mit der rechten Maustaste auf den Knoten Verweise, und wählen Sie Verweise bearbeiten... und wechseln Sie dann wie gezeigt zur Registerkarte Projekte:

Hinzufügen eines Verweises zu einer PCL über die Option Verweise bearbeiten

Der folgende Screenshot zeigt das Projektmappenpad für die TaskyPortable-Beispiel-App mit der PCL-Bibliothek am unteren Rand und einem Verweis auf diese PCL-Bibliothek im Xamarin.iOS-Projekt.

TaskyPortable-Beispiellösung mit PCL-Projekt

Die Ausgabe einer PCL (also die resultierende Assembly-DLL) kann auch als Verweis auf die meisten Projekte hinzugefügt werden. Dies macht PCL zu einer idealen Möglichkeit, plattformübergreifende Komponenten und Bibliotheken auszuliefern.

PCL-Beispiel

Die TaskyPortable-Beispielanwendung veranschaulicht, wie eine portable Klassenbibliothek mit Xamarin verwendet werden kann. Hier sind einige Screenshots der resultierenden Apps, die unter iOS und Android ausgeführt werden:

Hier sind einige Screenshots der resultierenden Apps, die unter iOS, Android und Windows Phone

Es verwendet eine Reihe von Daten- und Logikklassen, die rein portierbaren Code sind, und zeigt auch, wie plattformspezifische Anforderungen mithilfe von Abhängigkeitsinjektion für die SQLite-Datenbankimplementierung integriert werden.

Die Lösungsstruktur ist unten (in Visual Studio für Mac bzw. Visual Studio) dargestellt:

Die Lösungsstruktur wird hier in Visual Studio für Mac bzw. Visual Studio angezeigt.

Da der SQLite-NET-Code zu Demonstrationszwecken plattformspezifische Teile enthält (zum Arbeiten mit den SQLite-Implementierungen unter den verschiedenen Betriebssystemen), wurde er zu einer abstrakten Klasse umgestaltet, die in eine portable Klassenbibliothek kompiliert werden kann, und der tatsächliche Code, der als Unterklassen in den iOS- und Android-Projekten implementiert wird.

TaskyPortableLibrary

Die portable Klassenbibliothek ist in den .NET-Features eingeschränkt, die sie unterstützen kann. Da es für die Ausführung auf mehreren Plattformen kompiliert ist, kann es keine Funktionalität nutzen, die [DllImport] in SQLite-NET verwendet wird. Stattdessen wird SQLite-NET als abstrakte Klasse implementiert und dann über den Rest des freigegebenen Codes referenziert. Ein Extrakt der abstrakten API ist unten dargestellt:

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

}

Der Rest des freigegebenen Codes verwendet die abstrakte Klasse zum "Speichern" und "Abrufen" von Objekten aus der Datenbank. In jeder Anwendung, die diese abstrakte Klasse verwendet, müssen wir eine vollständige Implementierung übergeben, die die tatsächliche Datenbankfunktionalität bereitstellt.

TaskyAndroid und TaskyiOS

Die iOS- und Android-Anwendungsprojekte enthalten die Benutzeroberfläche und anderen plattformspezifischen Code, der zum Verknüpfen des freigegebenen Codes in der PCL verwendet wird.

Diese Projekte enthalten auch eine Implementierung der abstrakten Datenbank-API, die auf dieser Plattform funktioniert. Unter iOS und Android ist die Sqlite-Datenbank-Engine in das Betriebssystem integriert, sodass die Implementierung wie gezeigt verwendet [DllImport] werden kann, um die konkrete Implementierung der Datenbankkonnektivität bereitzustellen. Hier finden Sie einen Auszug aus dem plattformspezifischen Implementierungscode:

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

Die vollständige Implementierung ist im Beispielcode zu sehen.

Zusammenfassung

In diesem Artikel wurden kurz die Vorteile und Fallstricke von portablen Klassenbibliotheken erläutert, das Erstellen und Nutzen von PCLs in Visual Studio für Mac und Visual Studio veranschaulicht und schließlich eine vollständige Beispielanwendung – TaskyPortable – vorgestellt, die eine PCL in Aktion zeigt.