ApiInformation是否不尊重应用目标版本

想象一下以下设置:

UWP图书馆:
MinVersion:10240
TargetVersion:16299

此库在运行时检查是否存在UniversalApiContract版本5。
如果是,它将使用新的NavigationView控件。

UWP应用程序:
MinVersion:10240
TargetVersion:10240

此应用程序引用UWP库项目。
当我在安装了Windows 10版本16299的计算机上运行此应用程序时,会发生以下情况:
UWP库在运行时检查api合约。 因为我有最新版本的Windows 10,是的它存在。
然后它尝试创建NavigationView控件,我得到一个TypeLoadException,消息无法找到Windows运行时类型’Windows.UI.Xaml.Controls.NavigationView’。

什么? 为什么? ApiInformation类是否不尊重正在运行的应用程序的目标版本?

我该怎么做才能解决这个问题?
我认为ApiInformation是避免这种情况的方法,但显然不是吗?!

这是一个展示错误的Github存储库:
https://github.com/haefele/ApiInformationTargetVersionFail

如果将MyApp项目的目标版本设置为16299,则一切正常。

[编辑2018年5月29日]

ApiInformation类型的方法基于磁盘上WinRT元数据的简单查找 – 如果元数据存在,则调用成功。 这样可以在不增加最低版本的情况下“点亮”新平台上的新function。 但重要的是, ApiInformation对API的实现一无所知:有时它可能会丢失(例如,在操作系统的早期“内部”版本中),有时它可能由于“怪癖”而无法工作(参见下面的示例)。 由于JIT和.NET Native工具链的工作方式,.NET也有不同的世界观。

这可能会导致问题……

.NET应用程序使用“Union WinMD”的概念,它是Windows SDK中存在的所有已知类型(包括扩展SDK)的联合,对应于应用程序的MaxVersionTested设置。 如果您在低级平台上运行应用程序, ApiInformation将告诉您API不存在,但.NET仍然可以基于Union WinMD进行JIT方法并执行一些reflection任务。 如果您实际尝试调用API(因为您忘记了ApiInformation检查),您将在运行时获得MissingMethodException ,因为API实际上并不存在。

如果在较低版本的应用程序中包含较高版本的.NET库,然后尝试在较高版本的操作系统上运行它,则可能会出现另一个问题。 在这种情况下, ApiInformation将成功,因为该类型存在于系统元数据中,但.NET将在运行时抛出MissingMethodException ,因为用于构建应用程序的Union WinMD中不存在该类型

重要提示:这是基于应用程序的目标版本(又名MaxVersionTested ),而不是库!

如果您构建应用程序的发行版,您甚至会看到.NET Native工具链在“输出”窗口中显示如下警告:

warning : ILTransform : warning ILT0003: Method 'Foo.Bar()' will always throw an exception due to the missing method 'SomeNewType.NewMethod()'. There may have been a missing assembly.

除了使用与库相同的目标版本构建应用程序(以便它可以解析所有引用)之外,没有什么好办法。

您可能遇到的另一个问题是当您的应用程序(或它所使用的库)使用“未来”的API时,这些API在应用程序的MaxVersionTested中列出的操作系统中不存在。 许多API都可以使用,但有些API并不是因为与运行应用程序的模拟传统模式不兼容。

图书馆问题的假设例子

想象一下,操作系统的X版本只支持黑白应用程序,其中背景总是白色,文本,图形等总是黑色。 应用程序是使用这个基本假设构建的 – 包括只分配每像素1位的图形缓冲区,或者从不担心文本不可见,因为背景颜色和前景色相同。 一切都好。

现在,操作系统的版本Y出来了,它支持彩色图形(例如,每像素8位)。 除了这个新function外,还有一对新的API, SetForegroundColor()SetBackgroundColor()可以让你选择你想要的任何颜色。 任何询问ApiInformation是否存在这两个新API的应用程序(或库)都在操作系统的版本Y上成功 ,并且任何MaxVersionTested至少为Y的应用程序都可以成功使用它们。 但出于兼容性原因, 它们无法在仅针对X版本的应用程序中工作 ,因为它不知道颜色存在。 它们的图形缓冲区大小错误,文本可能变得不可见,依此类推。 因此,当在X目标应用程序中使用时,API将在运行时失败,即使操作系统具有支持它们的元数据(和实现)。

不幸的是,今天没有好办法处理这种情况,但这种情况相对罕见。 它相当于使用LoadLibrary / GetProcAddress (或使用reflection的传统.NET库)来发现“来自未来”的API的传统Win32库。