想象以下设置:
UWP库:
最低版本:10240
目标版本:16299
该库在运行时检查是否存在UniversalApiContract版本5.
如果是,它将使用新的NavigationView控件.
UWP应用:
最低版本:10240
目标版本:10240
该应用程序引用了UWP Library项目.
当我在装有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日编辑]
the ApiInformation
type的方法基于对磁盘上WinRT元数据的简单查找-如果存在元数据,则调用成功.这可以在不增加最低版本的情况下“点亮”新平台上的新功能.不过重要的是ApiInformation对API的实现一无所知:有时可能会丢失(例如,在早期的“ Insider”操作系统构建中),有时可能由于“怪癖”而无法工作(请参见下面的示例).由于JIT和.NET Native工具链的工作方式,.NET也对世界有不同的看法.
这可能会导致问题…
.NET应用程序使用“联合WinMD”的概念,该概念是Windows SDK中存在的与应用程序的MaxVersionTested设置相对应的所有已知类型(包括扩展SDK)的并集.如果您在下层平台上运行该应用程序,则ApiInformation会告诉您该API不存在,但是.NET仍然可以基于Union WinMD来JIT方法并执行一些反射任务.如果您实际上尝试调用该API(因为您忘记了ApiInformation检查),则在运行时会收到MissingMethodException,因为该API实际上并不存在.
如果在较低版本的应用程序中包含较高版本的.NET库,然后尝试在较高版本的OS上运行它,则可能会出现其他问题.在这种情况下,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都可以使用,但由于与运行应用程序的模拟旧版模式不兼容而无法使用.
图书馆问题的假想例子
想象一下,该操作系统的X版本仅支持黑白应用程序,其中背景始终为白色,而文本,图形等始终为黑色.应用程序是基于这种基本假设而构建的-包括具有仅分配每个像素1位的图形缓冲区,或者永远不必担心文本是不可见的,因为背景和前景色是相同的.一切顺利.
现在,该操作系统的版本Y出现了,它支持彩色图形(例如,每像素8位).除此新功能外,还提供了一对新的API,SetForegroundColor()和SetBackgroundColor(),可让您选择所需的颜色.任何询问ApiInformation是否存在这两个新API的应用程序(或库)都将在操作系统的Y版本上成功,并且任何MaxVersionTested至少为Y的应用程序都可以成功使用它们.但是出于兼容性的原因,它们不能在仅以版本X为目标的应用程序中工作,因为它不存在颜色.它们的图形缓冲区大小错误,其文本可能变得不可见,依此类推.因此,即使在操作系统具有支持它们的元数据(和实现)的情况下,在面向X的应用中使用这些API时,它们也会在运行时失败.
不幸的是,今天没有很好的方法来处理这种情况,但这是相对罕见的情况.它等效于使用LoadLibrary / GetProcAddress的旧版Win32库(或使用反射的旧版.NET库)来发现“未来”的API.