Xamarin.iOS 的限制

由于使用 Xamarin.iOS 的应用程序被编译为静态代码,因此无法使用任何需要在运行时生成代码的工具。

与桌面 Mono 相比,Xamarin.iOS 存在以下限制:

有限的泛型支持

与传统的 Mono/.NET 不同,iPhone 上的代码是提前静态编译的,而不是由 JIT 编译器按需编译。

Mono 的完整 AOT 技术在泛型方面存在一些限制,这是因为并非所有可能的泛型实例化都可以在编译时预先确定。 对于常规 .NET 或 Mono 运行时而言,这并不是一个问题,因为代码始终使用实时编译器在运行时编译。 但这对 Xamarin.iOS 之类的静态编译器提出了挑战。

开发人员遇到的一些常见问题包括:

NSObject 的泛型子类有限制

Xamarin.iOS 目前对创建 NSObject 类的泛型子类的支持有限,例如不支持泛型方法。 从版本 7.2.1 开始,可以使用 NSObjects 的泛型子类,如下所示:

class Foo<T> : UIView {
    [..]
}

注意

虽然可以使用 NSObject 的泛型子类,但也存在一些限制。 有关详细信息,请阅读 NSObject 的泛型子类文档

无动态代码生成

由于 iOS 内核阻止应用程序动态生成代码,因此 Xamarin.iOS 不支持任何形式的动态代码生成。 这些设置包括:

  • System.Reflection.Emit 不可用。
  • 不支持 System.Runtime.Remoting。
  • 不支持动态创建类型(不支持 Type.GetType ("MyType`1")),尽管可以正常查找现有的类型(例如 Type.GetType ("System.String"))。
  • 反向回调必须在编译时向运行时注册。

System.Reflection.Emit

缺少 System.Reflection。 “发出”意味着依赖于运行时代码生成的代码将无法工作。 这包括:

  • 动态语言运行时。

  • 基于动态语言运行时构建的任何语言。

  • Remoting 的 TransparentProxy 或任何其他会导致运行时动态生成代码的内容。

    重要

    不要将 Reflection.Emit 与 Reflection 相混淆。 Reflection.Emit 涉及到动态生成代码并将该代码进行 JIT 处理,然后编译为本机代码。 由于 iOS 的限制(无 JIT 编译),不支持此功能。

但是,整个 Reflection API,包括 Type.GetType ("someClass")、列出方法、列出属性、提取属性和值的操作都可以正常运行。

使用委托调用本机函数

若要通过 C# 委托调用本机函数,委托的声明必须使用以下属性之一进行修饰:

不提供这些属性之一会导致运行时错误,例如:

System.ExecutionEngineException: Attempting to JIT compile method '(wrapper managed-to-native) YourClass/YourDelegate:wrapper_aot_native(object,intptr,intptr)' while running in aot-only mode.

反向回调

在标准 Mono 中,可以将 C# 委托实例传递给非托管代码来代替函数指针。 运行时通常会将这些函数指针转换为一个小 thunk,允许非托管代码回调托管代码。

在 Mono 中,这些桥是由实时编译器实现的。 使用 iPhone 所需的提前编译器时,此时有两个重要限制:

无远程处理

远程处理堆栈在 Xamarin.iOS 上不可用。

运行时禁用的功能

Mono 的 iOS 运行时中已禁用以下功能:

  • 探查器
  • Reflection.Emit
  • Reflection.Emit.Save 功能
  • COM 绑定
  • JIT 引擎
  • 元数据验证器(因为没有 JIT)

.NET API 限制

公开的 .NET API 是完整框架的子集,因为并非所有内容都在 iOS 中可用。 请参阅“常见问题解答”,了解目前支持的程序集列表

具体而言,Xamarin.iOS 使用的 API 配置文件不包括 System.Configuration,因此无法使用外部 XML 文件来配置运行时的行为。