【问题标题】:Assembly.GetCallingAssembly isn't supported on WinRT, but is for portable class libraries?WinRT 不支持 Assembly.GetCallingAssembly,但适用于可移植类库?
【发布时间】:2013-01-23 16:36:29
【问题描述】:
我需要获取一些关于调用我的组件的程序集的元数据。因此,使用Assembly.GetCallingAssembly() 似乎很自然。但是,我发现它在任何地方都可以使用,除了 Windows 应用商店。支持的地方:
但是,不支持它的地方是直接在 Windows 应用商店应用程序中。我可以制作一个可移植的类库,然后在 Windows 应用商店应用程序中从那里调用它,但我不能直接将它放在 Windows 应用商店应用程序/类库中。
是否有一种解决方法可以通过这种方式或其他方式获取Assembly 提供的元数据类型?
【问题讨论】:
标签:
.net
reflection
windows-runtime
windows-store-apps
portable-class-library
【解决方案1】:
Assembly.GetCallingAssembly 没有在 WinRT 中公开 - 据说是因为它的语义在面对内联等 (source) 时不可靠,但它也不太适合 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 应用商店应用中不可见是“我们希望这会消失”。
(这个答案只涉及“我可以”而不是“我应该”)。
【解决方案2】:
该方法被取消只是因为它在 WinRT 应用程序中太不可靠了。 WinRT 的一个强大设计目标是使不同语言运行时环境之间的互操作变得简单且无故障。效果很好,您可以轻松地以 C# 等语言创建 WinRT 组件,并让以 C++ 或 Javascript 等非托管语言编写的应用程序使用它。
这在桌面 .NET 应用程序中也是可能的,但要复杂得多,必须回退到 [ComVisible] 程序集或使用 C++/CLI 语言创建混合模式程序集。在这种情况下使用 Assembly.GetCallingAssembly() 也会失败,但是程序员完全认为它会失败,因为他很清楚要做一些特别的事情。
这在 WinRT 组件中变得更加模糊。特别是因为如果调用实际上是从另一个 .NET 程序集发出的,则它不一定会失败。但是当它来自非托管代码时就没有希望了。
这种随机的失败是完全的痛苦,没有一个像样的解决方法。因此,该方法被取消。使用 PCL 是一种可能的解决方法,但微软过去曾严厉警告过,这种黑客行为是非常不推荐的。它被商店验证程序捕获并导致拒绝的可能性非零。