提问人:Christopher Painter 提问时间:11/24/2022 最后编辑:Christopher Painter 更新时间:11/26/2022 访问量:282
为什么使用反射后在 .NET 7 中出现强制转换错误?
Why am I getting a casting error in .NET 7 after using reflection?
问:
.NET 7 和 .NET Framework 中的反射和强制转换是否不同?我正在移植一个项目,并在移动代码后出现此强制转换错误。奇怪的是,这个类实现了该接口。此代码适用于 .NET 4.x。
foreach (Assembly pluginAssembly in pluginAssemblies)
{
try
{
// Look for class(s) with our interface and construct them
foreach (var type in pluginAssembly.GetTypes())
{
Type iDesigner = type.GetInterface(typeof(IFireworksDesigner).FullName);
if (iDesigner != null)
{
object instance = Activator.CreateInstance(type); // creates an object
IFireworksDesigner designer = (IFireworksDesigner)instance; // throws an exception
// do stuff
}
}
}
catch(Exception ex)
{
//Something really bad must have happened.
MessageBox.Show("Fatal error reflecting plugins in assembly '" + pluginAssembly.FullName + "'.\r\n" +
"The error message is:\r\n\r\n" + ex.Message);
}
}
更新:我在 https://github.com/chrpai/reflection 上制作了一个示例存储库
使用调用 .NET Standard 2.0 的 FW48 EXE 即可正常工作。 使用 Core7 EXE 调用 .NET Standard 2.0 或 .NET 7 DLL 时,它将失败。
答:
我明白了原因,结论是类实现的接口和你试图转换的接口存在于不同的 s 中,所以它失败了。AssemblyLoadContext
详
LoadFile 不会将文件加载到加载自上下文中
这意味着将程序集加载到新的上下文中,源代码也会验证这一点。LoadFile
AssemblyLoadContext alc = new IndividualAssemblyLoadContext($"Assembly.LoadFile({normalizedPath})");
result = alc.LoadFromAssemblyPath(normalizedPath);
加载 LibCore.dll 后,程序中存在 2 个,它们都有一个同名和相同程序集名称的接口。因此,即使使用代码也无法区分不同的上下文。LoadFile
AssemblyLoadContext
IPlugin
type.GetInterface(typeof(IPlugin).FullName)
AssemblyQualifiedName
使用以下代码进行验证。
// IndividualAssemblyLoadContext #2
Console.WriteLine(AssemblyLoadContext.GetLoadContext(iDesigner.Assembly));
// DefaultAssemblyLoadContext #0
Console.WriteLine(AssemblyLoadContext.GetLoadContext(typeof(IPlugin).Assembly));
解决方案 1
使用代替 . 将程序集加载到加载自上下文中,以便可以共享接口。LoadFrom
LoadFile
LoadFrom
pluginAssemblies.Add(Assembly.LoadFrom(file));
解决方案 2
使用独立核心库,例如,您可以有 3 个项目。
ConsoleCoreCore.exe
LibCore.dll
public interface IPlugin
public class Server
Lib1.dll
public class LibStandardPlugin : IPlugin
Lib1.dll 和 ConsoleCoreCore.exe 都引用 LibCore.dll
ConsoleCoreCore.exe -> LibCore.dll <- Lib1.dll
现在,如果您从 LibCore.dll 加载 Lib1.dll ,Lib1.dll 将被加载到独立上下文中,但它的接口仍然是来自 LibCore.dll 的接口。 LoadFile
IPlugin
// IndividualAssemblyLoadContext #1
Console.WriteLine(AssemblyLoadContext.GetLoadContext(type.Assembly));
// DefaultAssemblyLoadContext #0
Console.WriteLine(AssemblyLoadContext.GetLoadContext(iDesigner.Assembly));
// DefaultAssemblyLoadContext #0
Console.WriteLine(AssemblyLoadContext.GetLoadContext(typeof(IPlugin).Assembly));
评论
pluginAssembly.GetTypes()
将返回不可构造的类型,例如类型和类型,以及没有无参数构造函数的类型。您需要先检查是否可以构造。interface
abstract class
class
var type
.Name
.AssemblyQualifiedName
.FullName
Type.GetInterface(String)
Object DataSource