我需要获取一些关于调用我的组件的程序集的元数据。因此,使用Assembly.GetCallingAssembly()
似乎是很自然的选择。但是,我发现它适用于除Windows应用商店以外的任何地方。支持的地方:
- 电话 7.0+
- .Net 1.0+
- 可移植类库
但是,不支持的地方直接在 Windows 应用商店应用程序中。我可以创建一个可移植的类库,然后从 Windows 应用商店应用程序内部调用它,但我不能直接将其放在 Windows 应用商店应用/类库中。
是否有解决此问题或其他方法来获取Assembly
提供的元数据类型?
Assembly.GetCallingAssembly
不会在 WinRT 中公开 - 据说是因为它的语义在面对内联等(源)时不可靠,但它也不太符合 Windows 应用商店应用中允许的限制反射。你可以得到类似 Assembly.GetCurrentAssembly()
,例如这样:
typeof(MainPage).GetTypeInfo().Assembly
但这根本不一样。使用受限反射模型,也无法在运行时获取堆栈跟踪,就像在 .NET 中一样。
至于可移植类库,我正要说Assembly.GetCurrentAssembly()
在可移植类库中通常受支持,但在 WinRT 中不受支持 - 如果它根本不在该平台中,这将是有意义的。但实际上,它似乎存在于除 WinRT+ 之外的所有配置文件中,包括 WinRT。NET4.5 - 似乎这里必须对这种不一致进行某种疏忽。因此,该方法存在于 WinRT 中(此外,没有进行任何类型的重定向),但在编译时可用的元数据中不可见。
因此,您可以使用反射调用该方法:
var assembly = (Assembly) typeof(Assembly).GetTypeInfo()
.GetDeclaredMethod("GetCallingAssembly")
.Invoke(null, new object[0]);
我认为此方法在 Windows 应用商店应用程序中的不可见性是"我们希望这种情况会消失"。
(这个答案只涉及"我能"而不是"我应该")。
被削减只是因为它在 WinRT 应用中太不可靠。 WinRT 的一个主要设计目标是使不同语言运行时环境之间的互操作变得简单且无故障。 这很有效,你可以轻松地使用 C# 等语言创建 WinRT 组件,并让使用非托管语言(如 C++ 或 Javascript)编写的应用使用它。
这在桌面 .NET 应用中也是可能的,但它要复杂得多,必须回退到 [ComVisible] 程序集或使用 C++/CLI 语言创建混合模式程序集。 在这种情况下使用 Assembly.GetCallingAssembly() 也会失败,然而程序员完全预计会失败,因为他很清楚要做一些特别的事情。
这在 WinRT 组件中变得更加模糊。 特别是因为如果调用实际上是从另一个 .NET 程序集进行的,则不一定失败。 但是当它来自非托管代码时,没有希望。
这种随机的失败只是完全的痛苦,没有像样的解决方法。 因此,该方法被切断了。 使用 PCL 是一种可能的解决方法,但Microsoft过去曾严厉警告说,强烈建议不要使用这种黑客攻击。 它被商店验证程序捕获并导致拒绝的几率不为零。