Fehlende .NET-APIs in Unity und UWP

Beim Erstellen eines UWP-Spiels mit .NET stellen Sie möglicherweise fest, dass einige APIs, die Sie möglicherweise im Unity-Editor oder für ein eigenständiges PC-Spiel verwenden, für UWP nicht vorhanden sind. Das liegt daran, dass .NET für UWP-Apps eine Teilmenge der Typen enthält, die im vollständigen .NET Framework für jeden Namespace bereitgestellt werden.

Darüber hinaus verwenden einige Spiele-Engines unterschiedliche .NET-Varianten, die nicht vollständig mit .NET für UWP kompatibel sind, z. B. Unity Mono. Wenn Sie also Ihr Spiel schreiben, funktioniert möglicherweise alles im Editor, aber wenn Sie zum Erstellen für UWP gehen, erhalten Sie möglicherweise Fehler wie die folgende: Der Typ oder Namespace "Formatter" ist im Namespace "System.Runtime.Serialization" nicht vorhanden (fehlt ein Assemblyverweis?)

Glücklicherweise stellt Unity einige dieser fehlenden APIs als Erweiterungsmethoden und Ersatztypen bereit, die unter Universelle Windows-Plattform: Fehlende .NET-Typen im .NET-Skripting-Back-End beschrieben werden. Wenn die von Ihnen benötigte Funktionalität jedoch nicht vorhanden ist, wird in der Übersicht über .NET for Windows 8.x-Apps erläutert, wie Sie Ihren Code konvertieren können, um WinRT oder .NET für Windows-Runtime-APIs zu verwenden. (Es wird Windows 8 erläutert, gilt aber auch für Windows 10 UWP-Apps.)

.NET Standard

Um zu verstehen, warum einige APIs möglicherweise nicht funktionieren, ist es wichtig, die verschiedenen .NET-Varianten zu verstehen und zu verstehen, wie UWP .NET implementiert. .NET Standard ist eine formale Spezifikation von .NET-APIs, die plattformübergreifend sein soll und die verschiedenen .NET-Varianten vereinheitlichen soll. Jede Implementierung von .NET unterstützt eine bestimmte Version von .NET Standard. Eine Tabelle mit Standards und Implementierungen finden Sie unter .NET-Implementierungsunterstützung.

Jede Version des UWP SDK entspricht einer anderen Ebene von .NET Standard. Das SDK 16299 (Fall Creators Update) unterstützt beispielsweise .NET Standard 2.0.

Wenn Sie wissen möchten, ob eine bestimmte .NET-API in der von Ihnen gewünschten UWP-Version unterstützt wird, können Sie die .NET Standard-API-Referenz überprüfen und die Version des .NET-Standards auswählen, die von dieser Version von UWP unterstützt wird.

Back-End-Konfiguration für Skripts

Das erste, was Sie tun sollten, wenn Sie Probleme beim Erstellen für UWP haben, ist die Überprüfung der Playereinstellungen (Dateibuildeinstellungen>, wählen Sie Universelle Windows-Plattform und dann Playereinstellungen aus). Unter Konfiguration mit anderen Einstellungen >sind die ersten drei Dropdownlisten (Skriptlaufzeitversion, Skript-Back-End und Api-Kompatibilitätsgrad) wichtige Einstellungen, die berücksichtigt werden sollten.

Die Scripting Runtime-Version verwendet das Unity-Skripting-Back-End, mit dem Sie die (ungefähr) gleichwertige Version von .NET Framework unterstützung abrufen können, die Sie auswählen. Beachten Sie jedoch, dass nicht alle APIs in dieser Version der .NET Framework unterstützt werden, nur die APIs in der Version von .NET Standard, auf die Ihre UWP abzielt.

Bei neuen .NET-Releases werden häufig weitere APIs zu .NET Standard hinzugefügt, sodass Sie denselben Code für eigenständige Versionen und UWP verwenden können. Beispielsweise wurde der System.Runtime.Serialization.Json-Namespace in .NET Standard 2.0 eingeführt. Wenn Sie die Scripting Runtime-Version auf .NET 3.5 Equivalent (die auf eine frühere Version von .NET Standard abzielt) festlegen, erhalten Sie eine Fehlermeldung, wenn Sie versuchen, die API zu verwenden. Wechseln Sie zu .NET 4.6 Equivalent (unterstützt .NET Standard 2.0), und die API funktioniert.

Das Skript-Back-End kann .NET oder IL2CPP sein. Für dieses Thema gehen wir davon aus, dass Sie .NET ausgewählt haben, da hier die hier behandelten Probleme auftreten. Weitere Informationen finden Sie unter Skripterstellung für Back-Ends .

Schließlich sollten Sie den Api-Kompatibilitätsgrad auf die Version von .NET festlegen, unter der Ihr Spiel ausgeführt werden soll. Dies sollte mit der Scripting Runtime-Version übereinstimmen.

Im Allgemeinen sollten Sie für Die Version der Skriptlaufzeit und den Api-Kompatibilitätsgrad die neueste verfügbare Version auswählen, um mehr Kompatibilität mit dem .NET Framework zu haben und ihnen somit die Verwendung weiterer .NET-APIs zu ermöglichen.

Konfiguration: Skriptversion der Runtime; Skript-Back-End; API-Kompatibilitätsgrad

Plattformabhängige Kompilierung

Wenn Sie Ihr Unity-Spiel für mehrere Plattformen erstellen, einschließlich UWP, sollten Sie die plattformabhängige Kompilierung verwenden, um sicherzustellen, dass der für UWP vorgesehene Code nur ausgeführt wird, wenn das Spiel als UWP erstellt wird. Auf diese Weise können Sie den vollständigen .NET Framework für eigenständige Desktop- und andere Plattformen und WinRT-APIs für UWP verwenden, ohne Dass Buildfehler auftreten.

Verwenden Sie die folgenden Anweisungen, um Code nur zu kompilieren, wenn Sie als UWP-App ausgeführt werden:

#if NETFX_CORE
    // Your UWP code here
#else
    // Your standard code here
#endif

Hinweis

NETFX_CORE dient nur dazu, zu überprüfen, ob Sie C#-Code für das .NET-Skript-Back-End kompilieren. Wenn Sie ein anderes Skript-Back-End verwenden, z. B. IL2CPP, verwenden Sie stattdessen ENABLE_WINMD_SUPPORT .

Häufig auftretende Probleme und Problemumgehungen

In den folgenden Szenarien werden häufige Probleme beschrieben, die auftreten können, wenn .NET-APIs in der UWP-Teilmenge fehlen, und Möglichkeiten, sie zu umgehen.

Datenserialisierung mit BinaryFormatter

Es ist üblich, dass Spiele Speichern von Daten serialisieren, sodass Spieler sie nicht einfach bearbeiten können. BinaryFormatter, der ein Objekt in binär serialisiert, ist jedoch in früheren Versionen von .NET Standard (vor 2.0) nicht verfügbar. Erwägen Sie stattdessen die Verwendung von XmlSerializer oder DataContractJsonSerializer .

private void Save()
{
    SaveData data = new SaveData(); // User-defined object to serialize

    DataContractJsonSerializer serializer = 
      new DataContractJsonSerializer(typeof(SaveData));

    FileStream stream = 
      new FileStream(Application.persistentDataPath, FileMode.CreateNew);

    serializer.WriteObject(stream, data);
    stream.Dispose();
}

E/A-Vorgänge

Einige Typen im System.IO-Namespace , z . B. FileStream, sind in früheren Versionen von .NET Standard nicht verfügbar. Unity stellt jedoch die Typen Directory, File und FileStream bereit, damit Sie sie in Ihrem Spiel verwenden können.

Alternativ können Sie die Windows.Storage-APIs verwenden, die nur für UWP-Apps verfügbar sind. Diese APIs beschränken die App jedoch auf das Schreiben in ihren spezifischen Speicher und gewähren ihr keinen freien Zugriff auf das gesamte Dateisystem. Weitere Informationen finden Sie unter Dateien, Ordner und Bibliotheken .

Ein wichtiger Hinweis ist, dass die Close-Methode nur in .NET Standard 2.0 und höher verfügbar ist (obwohl Unity eine Erweiterungsmethode bereitstellt). Verwenden Sie stattdessen Dispose .

Threading

Einige Typen in den System.Threading-Namespaces , z. B. ThreadPool, sind in früheren Versionen von .NET Standard nicht verfügbar. In diesen Fällen können Sie stattdessen den Windows.System.Threading-Namespace verwenden.

Hier erfahren Sie, wie Sie das Threading in einem Unity-Spiel mithilfe der plattformabhängigen Kompilierung behandeln können, um sich sowohl für UWP- als auch für Nicht-UWP-Plattformen vorzubereiten:

private void UsingThreads()
{
#if NETFX_CORE
    Windows.System.Threading.ThreadPool.RunAsync(workItem => SomeMethod());
#else
    System.Threading.ThreadPool.QueueUserWorkItem(workItem => SomeMethod());
#endif
}

Sicherheit

Einige der System.Security- * Namespaces, z . B. System.Security.Cryptography.X509Certificates, sind nicht verfügbar, wenn Sie ein Unity-Spiel für UWP erstellen. Verwenden Sie in diesen Fällen windows.Security. * APIs, die einen Großteil derselben Funktionalität abdecken.

Im folgenden Beispiel werden die Zertifikate einfach aus einem Zertifikatspeicher mit dem angegebenen Namen abgerufen:

private async void GetCertificatesAsync(string certStoreName)
    {
#if NETFX_CORE
        IReadOnlyList<Certificate> certs = await CertificateStores.FindAllAsync();
        IEnumerable<Certificate> myCerts = 
            certs.Where((certificate) => certificate.StoreName == certStoreName);
#else
        X509Store store = new X509Store(certStoreName, StoreLocation.CurrentUser);
        store.Open(OpenFlags.OpenExistingOnly);
        X509Certificate2Collection certs = store.Certificates;
#endif
    }

Weitere Informationen zur Verwendung der WinRT-Sicherheits-APIs finden Sie unter Sicherheit .

Netzwerk

Einige der System.Net. * Namespaces, z . B. System.Net.Mail, sind auch beim Erstellen eines Unity-Spiels für UWP nicht verfügbar. Verwenden Sie für die meisten dieser APIs die entsprechende Windows.Networking-Instanz. * und Windows.Web. * WinRT-APIs, um ähnliche Funktionen zu erhalten. Weitere Informationen finden Sie unter Netzwerk und Webdienste .

Verwenden Sie im Fall von System.Net.Mail den Namespace Windows.ApplicationModel.Email. Weitere Informationen finden Sie unter Senden von E-Mails .

Siehe auch