[英]Why am I getting a casting error in .NET 7 after using reflection?
Is reflection and casting different in .NET 7 vs .NET Framework? .NET 7 与 .NET 框架中的反射和投射是否不同? I'm porting a project and getting this casting error after moving the code over.
我正在移植一个项目并在移动代码后收到此转换错误。 The wierd thing is this class implements that interface.
奇怪的是这个 class 实现了那个接口。 This code works in .NET 4.x.
此代码适用于 .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);
}
}
Update: I've made a sample repos at https://github.com/chrpai/reflection更新:我在https://github.com/chrpai/reflection做了一个样本回购
With a FW48 EXE calling .NET Standard 2.0 it works.使用调用 .NET Standard 2.0 的 FW48 EXE,它可以工作。 With a Core7 EXE calling either a .NET Standard 2.0 or .NET 7 DLL it fails.
使用调用 .NET Standard 2.0 或 .NET 7 DLL 的 Core7 EXE 失败。
I got the reason, the conclusion is the interface the class implemented and the interface you try to cast to exist in different AssemblyLoadContext
s, so it fails.我明白了,结论是 class 实现的接口和您尝试转换为存在于不同的
AssemblyLoadContext
中的接口,因此它失败了。
The documentation of LoadFile
says: LoadFile
的文档说:
LoadFile does not load files into the load-from context
LoadFile 不会将文件加载到加载源上下文中
That means LoadFile
will load an assembly into a new context, the source code also verifies this.这意味着
LoadFile
会将程序集加载到新的上下文中, 源代码也验证了这一点。
AssemblyLoadContext alc = new IndividualAssemblyLoadContext($"Assembly.LoadFile({normalizedPath})");
result = alc.LoadFromAssemblyPath(normalizedPath);
After you load LibCore.dll by LoadFile
, there are 2 AssemblyLoadContext
s exist in the program, both of them have an interface IPlugin
with the same name and same assembly name.通过
LoadFile
加载LibCore.dll后,程序中存在 2 个AssemblyLoadContext
,它们都有一个具有相同名称和相同程序集名称的接口IPlugin
。 So the code type.GetInterface(typeof(IPlugin).FullName)
even using AssemblyQualifiedName
is not able to distinguish between different contexts.所以代码
type.GetInterface(typeof(IPlugin).FullName)
即使使用AssemblyQualifiedName
也无法区分不同的上下文。
Using the following code to verify.使用下面的代码来验证。
// IndividualAssemblyLoadContext #2
Console.WriteLine(AssemblyLoadContext.GetLoadContext(iDesigner.Assembly));
// DefaultAssemblyLoadContext #0
Console.WriteLine(AssemblyLoadContext.GetLoadContext(typeof(IPlugin).Assembly));
Use LoadFrom
instead of LoadFile
.使用
LoadFrom
而不是LoadFile
。 LoadFrom
loads an assembly into load-from context, so the interface can be shared. LoadFrom
将程序集加载到加载源上下文中,因此可以共享接口。
pluginAssemblies.Add(Assembly.LoadFrom(file));
Use an individal core library, for example you can have 3 projects.使用单独的核心库,例如您可以有 3 个项目。
ConsoleCoreCore.exe
LibCore.dll
public interface IPlugin
public class Server
Lib1.dll
public class LibStandardPlugin : IPlugin
Both Lib1.dll and ConsoleCoreCore.exe refer to LibCore.dll Lib1.dll和ConsoleCoreCore.exe都是指LibCore.dll
ConsoleCoreCore.exe -> LibCore.dll <- Lib1.dll
Now if you load Lib1.dll from LibCore.dll by LoadFile
, Lib1.dll will be loaded into an individal context, but its IPlugin
interface is still the one from LibCore.dll .现在,如果您通过
LoadFile
从LibCore.dll加载Lib1.dll ,则Lib1.dll将被加载到一个单独的上下文中,但其IPlugin
接口仍然是来自LibCore.dll的接口。
// 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));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.