c# - 如何确保 typeof 和强制转换运算符在不同的加载上下文而不是默认加载上下文上运行

标签 c# .net reflection .net-core f#

我正在使用 .NET core 并尝试将通过反射加载到程序集加载上下文(不是默认加载上下文)中的类型与已知的编译时类型进行比较。但是,如果我像这样使用 typeof 运算符:

if(x.GetType() == typeof(KnownType))

即使两种类型的所有属性(包括它们加载的位置相同),结果也始终为 false,大概是因为它们加载到不同的加载上下文中......自定义上下文和默认上下文。

我可以通过将已知类型或接口(interface)预加载到自定义上下文中、获取对其的引用并进行比较来使其工作,如下所示:

   if(x.GetType() == preloadedKnownType)

但是,我的 Actor 也有类似的情况。如果我这样做:

   var y = x as KnownType

转换失败,可能是因为它们被加载到不同的上下文中。

是否可以使用 typeof 和强制转换运算符将类型加载到自定义上下文中?

最佳答案

如果将程序集加载到不同的 AssemblyLoadContext 中,其想法通常是隔离类型。即使二进制文件相同,代码也会将其视为不同的。这意味着类型实例不同 ( see docs )。

typeof 运算符在编译时进行检查,因此该类型必须存在。它不会突然与您的动态加载类型匹配,因为如上所述,这些类型是不同的实例。

因此,您的检查 if(x.GetType() == typeof(KnownType)) 失败是预期的行为。


AssemblyLoadContext 的一个好处是您还可以共享依赖项。如果您在库中提供类型并在两个上下文中共享该程序集,则可以检查这些类型。

例如。考虑以下接口(interface)和类:

// Located in Library.DLL
public interface SomeInterface
{
    string SomeValue { get; }
}
// Located in Main.DLL
public class KnownType : SomeInterface
{
    public string SomeValue => $"{this.GetType().Name} ({this.GetType().GetHashCode()})";
}
// Get the types
var localType = typeof(KnownType);
var loadedType = Assembly.LoadFile(Assembly.GetExecutingAssembly().Location).GetType(localType.FullName);

Console.WriteLine($"{localType} {localType.GetHashCode()}");   // PRINTS: Main.KnownType 58225482
Console.WriteLine($"{loadedType} {loadedType.GetHashCode()}"); // PRINTS: Main.KnownType 54267293
Console.WriteLine($"Comparison: {loadedType == localType}");   // PRINTS: Comparison: False

// Create instances
var localInstance = Activator.CreateInstance(localType) as SomeInterface;
var loadedInstance = Activator.CreateInstance(loadedType) as SomeInterface;

Console.WriteLine(localInstance.SomeValue);  // PRINTS: KnownType (58225482)
Console.WriteLine(loadedInstance.SomeValue); // PRINTS: KnownType (54267293)

简而言之,Assembly.LoadFile 会将目标程序集加载到新的 AssemblyLoadContext 中,将其与默认上下文隔离。由于此 AssemblyLoadContext 中不存在依赖关系解析器,因此它将仅重用已加载的已知库程序集。

执行此代码时,哈希码和比较显示,在运行时,类型实例不同,即使它是完全相同的 DLL。但是,由于它们实现了共享程序集中的接口(interface) (SomeInterface),因此两个对象都可以转换为该接口(interface)并使用。

请参阅有关使用 AssemblyLoadContext 的指南 here 。它还解释了如果您有自定义 AssemblyLoadContext,如何在不同上下文之间共享依赖关系。

关于c# - 如何确保 typeof 和强制转换运算符在不同的加载上下文而不是默认加载上下文上运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58912559/

相关文章:

c# - AzureWebjobSDK 中的 StorageConnectionString 是否需要访问整个存储帐户?

c# - 实现自己的 "Factory"以在 WPF 中重用 View

.net - SMS网关设备

c# - 测试单个值的 [Flags] 枚举值

java - 通过反射将基类转换为派生类

c# - 版本控制服务契约(Contract)后无法访问 WCF 服务

c# - 如何在代码中将密码提供给 ADO.Net 实体数据模型中的连接字符串

c# - 什么是 async 和 await,什么时候在 Windows 开发中使用它们?

c# - 如何检索请求的操作方法的属性

java - 以通用方式重试方法调用