共用方式為


在跨平台應用程式中使用原生類型

本文涵蓋在跨平臺應用程式中使用新的 iOS 整合 API 原生類型(nint、nuint、nfloat),其中程式代碼會與 Android 或 Windows 電話 OS 等非 iOS 裝置共用。

64 種類型的原生類型適用於 iOS 和 Mac API。 如果您要撰寫在 Android 或 Windows 上執行的共用程式碼,則必須管理將整合類型轉換成您可以共用的一般 .NET 類型。

本文件討論從您共用/通用程式代碼與整合 API 互操作的不同方式。

使用原生型別的時機

Xamarin.iOS 和 Xamarin.Mac 整合 API 仍然包含 intuintfloat 資料類型,以及 RectangleFSizeFPointF 類型。 這些現有的數據類型應該繼續用於任何共用的跨平台程式代碼中。 只有在呼叫需要架構感知型別的 Mac 或 iOS API 時,才應該使用新的 Native 數據類型。

視共用的程式代碼本質而定,有時候可能需要跨平臺程式代碼來處理 nintnuintnfloat 數據類型。 例如:處理先前用來 System.Drawing.RectangleF 在 Xamarin.iOS 與 Xamarin.Android 版本應用程式之間共用功能的矩形數據轉換的連結庫,必須更新以處理 iOS 上的原生類型。

這些變更的處理方式取決於應用程式的大小和複雜度,以及已使用的程式代碼共用形式,如下列各節所示。

程式代碼共享考慮

如共用程式代碼選項檔中所述,跨平臺專案之間共用程式代碼有兩種主要方式:共用專案和可攜式類別庫。 已使用這兩種類型中的哪一種,將會限制我們在跨平臺程式代碼中處理原生數據類型時所擁有的選項。

可攜式類別庫專案

可攜式類別庫 (PCL) 可讓您以您想要支援的平臺為目標,並使用介面來提供平臺特定功能。

由於 PCL 專案類型已編譯為 .DLL ,而且沒有統一 API 的意義,因此您將被迫繼續使用 PCL 原始碼中的現有資料類型 (intuintfloat),並輸入將呼叫轉換成前端應用程式中 PCL 的類別和方法。 例如:

using NativePCL;
...

CGRect rect = new CGRect (0, 0, 200, 200);
Console.WriteLine ("Rectangle Area: {0}", Transformations.CalculateArea ((RectangleF)rect));

共用的專案

共用資產專案類型可讓您將原始程式碼組織在個別專案中,然後納入並編譯成個別平臺特定前端應用程式,並 #if 視需要使用編譯程式指示詞來管理平臺特定需求。

在跨平臺共用資產項目中選擇原生數據類型支援方法時,需要考慮使用共用程式碼的前端行動應用程式大小和複雜度,以及所共用程式碼的大小和複雜度。

根據這些因素,您可以使用 if __UNIFIED__ ... #endif 編譯程式指示詞實作下列類型的解決方案,以處理程式碼的整合 API 特定變更。

使用重複的方法

以在上述矩形數據上執行轉換的連結庫範例。 如果連結庫只包含一或兩個非常簡單的方法,您可以選擇為 Xamarin.iOS 和 Xamarin.Android 建立這些方法的重複版本。 例如:

using System;
using System.Drawing;

#if __UNIFIED__
using CoreGraphics;
#endif

namespace NativeShared
{
    public class Transformations
    {
        #region Constructors
        public Transformations ()
        {
        }
        #endregion

        #region Public Methods
        #if __UNIFIED__
            public static nfloat CalculateArea(CGRect rect) {

                // Calculate area...
                return (rect.Width * rect.Height);

            }
        #else
            public static float CalculateArea(RectangleF rect) {

                // Calculate area...
                return (rect.Width * rect.Height);

            }
        #endif
        #endregion
    }
}

在上述程式代碼中 CalculateArea ,由於例程非常簡單,因此我們已使用條件式編譯,並建立方法的個別整合 API 版本。 另一方面,如果連結庫包含許多例程或數個複雜的例程,則此解決方案不可行,因為它會呈現讓所有方法保持同步處理以進行修改或 Bug 修正的問題。

使用方法多載

在此情況下,解決方案可能是使用 32 位數據類型建立方法的多載版本,讓它們現在採用 CGRect 做為參數和/或傳回值、將該值 RectangleF 轉換為 (知道從 轉換為 nfloatfloat 是遺失轉換),並呼叫例程的原始版本來執行實際工作。 例如:

using System;
using System.Drawing;

#if __UNIFIED__
using CoreGraphics;
#endif

namespace NativeShared
{
    public class Transformations
    {
        #region Constructors
        public Transformations ()
        {
        }
        #endregion

        #region Public Methods
        #if __UNIFIED__
            public static nfloat CalculateArea(CGRect rect) {

                // Call original routine to calculate area
                return (nfloat)CalculateArea((RectangleF)rect);

            }
        #endif

        public static float CalculateArea(RectangleF rect) {

            // Calculate area...
            return (rect.Width * rect.Height);

        }

        #endregion
    }
}

同樣地,只要遺失精確度並不會影響應用程式特定需求的結果,這是很好的解決方案。

使用別名指示詞

對於遺失有效位數是問題的區域,另一個可能的解決方案是使用 using 指示詞建立 Native 和 CoreGraphics 數據類型的別名,方法是將下列程式代碼納入共用原始程式碼檔案頂端,並將任何所需的 intuintfloatnint轉換為 或 nuintnfloat

#if __UNIFIED__
    // Mappings Unified CoreGraphic classes to MonoTouch classes
    using RectangleF = global::CoreGraphics.CGRect;
    using SizeF = global::CoreGraphics.CGSize;
    using PointF = global::CoreGraphics.CGPoint;
#else
    // Mappings Unified types to MonoTouch types
    using nfloat = global::System.Single;
    using nint = global::System.Int32;
    using nuint = global::System.UInt32;
#endif

因此,我們的範例程式代碼會變成:

using System;
using System.Drawing;

#if __UNIFIED__
    // Map Unified CoreGraphic classes to MonoTouch classes
    using RectangleF = global::CoreGraphics.CGRect;
    using SizeF = global::CoreGraphics.CGSize;
    using PointF = global::CoreGraphics.CGPoint;
#else
    // Map Unified types to MonoTouch types
    using nfloat = global::System.Single;
    using nint = global::System.Int32;
    using nuint = global::System.UInt32;
#endif

namespace NativeShared
{

    public class Transformations
    {
        #region Constructors
        public Transformations ()
        {
        }
        #endregion

        #region Public Methods
        public static nfloat CalculateArea(RectangleF rect) {

            // Calculate area...
            return (rect.Width * rect.Height);

        }
        #endregion
    }
}

請注意,我們已在這裏變更 CalculateArea 方法以傳回 nfloat ,而不是標準 float。 如此一來,我們就不會收到編譯錯誤,嘗試以隱含方式將計算的結果(因為兩個乘數都是類型nfloat值)轉換成nfloatfloat回值。

如果程式代碼是在非整合 API 裝置上編譯並執行,則會 using nfloat = global::System.Single; 將 對應 nfloatSinglefloat ,其會隱含轉換成,讓取用的前端應用程式在不修改的情況下呼叫 CalculateArea 方法。

在前端應用程式中使用類型轉換

如果您的前端應用程式只對共用程式碼庫進行少數呼叫,另一個解決方案可能是讓連結庫維持不變,並在呼叫現有的例程時,在 Xamarin.iOS 或 Xamarin.Mac 應用程式中執行類型轉換。 例如:

using NativeShared;
...

CGRect rect = new CGRect (0, 0, 200, 200);
Console.WriteLine ("Rectangle Area: {0}", Transformations.CalculateArea ((RectangleF)rect));

如果取用的應用程式對共用程式代碼連結庫進行數百次呼叫,這再次可能不是很好的解決方案。

根據應用程式的架構,我們最終可能會使用上述一或多個解決方案來支援跨平台程序代碼中的原生數據類型(必要時)。

Xamarin.Forms 應用程式

若要將 Xamarin.Forms 用於也會與整合 API 應用程式共用的跨平臺 UI,則需要下列專案:

  • 整個解決方案必須使用 Xamarin.Forms NuGet 套件的 1.3.1 版(或更新版本)。
  • 針對任何 Xamarin.iOS 自定義轉譯,請根據 UI 程式代碼的共用方式(共用專案或 PCL)使用上述的相同類型解決方案。

如同標準跨平臺應用程式,在大部分情況下,現有的32位數據類型應該在任何共用的跨平台程序代碼中使用。 只有在呼叫需要架構感知類型的 Mac 或 iOS API 時,才應該使用新的原生數據類型。

如需詳細資訊,請參閱更新 現有的 Xamarin.Forms 應用程式 檔。

摘要

在本文中,我們已瞭解何時在整合 API 應用程式中使用原生數據類型及其跨平台的影響。 我們提供了數個解決方案,這些解決方案可用於新的原生數據類型必須用於跨平台連結庫的情況。 此外,我們也看到了在 Xamarin.Forms 跨平臺應用程式中支援整合 API 的快速指南。