调用 Assembly.GetType 时出现间歇性 TypeLoadException - 来自程序集的类型中的方法没有实现(仅在某些时候)
Intermittent TypeLoadException when calling Assembly.GetType - Method in type from assembly does not have an implementation (ONLY SOMETIMES)
在我的项目中,有一个带有抽象方法的抽象基class。
我们基于模式生成实现,然后使用 Assembly.LoadFrom
通过反射加载这些实现,然后调用 Assembly.GetType
以获得在另一个 DLL 中定义的接口的具体实现。
不同项目的结构(DLL文件):
Schema
- 包含类型定义
Base
- 具有由所有生成的实现共享的基础 class
Generated
- 生成的类型实现了 Base
的抽象基础 class 和 Schema
. 的接口
public interface IExample
{
//Some methods here, irrelevant to the problem
}
public abstract Base
{
protected abstract void SomeMethod(SomeType someArg); //This method is the method the exception specifies, but I suspect it's only because it's the first one in the file.
//More methods like the above, and some non-abstract/virtual methods too
}
public class Generated : Base, IExample
{
protected override void SomeMethod(SomeType someArg)
{
//Some implementation here
}
//More content here, not all of it being from either the interface or the Base type
}
var asm = Assembly.LoadFrom(path);
asm.GetType("SomeNameSpace.Generated"); //This is where it fails
在 Base 项目在不相关的区域更新并且它的版本升级之前,这工作正常。
它实现的接口类型正在请求生成的实现。 (类型定义中涉及泛型,不确定是否真的相关)
现在通常这将是一个简单的情况,“哦,您只需要重新编译它并再次包含它”,但令人兴奋的部分是这只是 有时 失败!
大约一半的时间,它都能正常工作。另一半,它抛出 TypeLoadException,认为该方法没有实现。
通常我希望它总是失败,但事实并非如此。
当然,包括新编译生成的 DLL 完全避免了这种情况。但我希望能够在不需要整个项目的情况下更新架构和基础项目。 (仅包含相关文件的 'service pack' 样式软件更新)
需要说明的是,none 涉及的类型已修改。没有“哦,我只是向方法添加了一个可选参数,所以它是相同的方法”错误。
唯一的变化是文件的其他部分。 Base
在一个大的 DLL 中,里面有很多不相关的实用程序。 Base
、IExample
和结果 Generated
仍然完全相同。如果是某些版本解析造成了破坏,我预计会出现问题。
遗憾的是,这不是一个简单的小项目,我可以打包成一个可重现的示例,而是一个具有许多层和模式的相当复杂的程序。我不确定我是否可以重现这个,当程序开始加载东西和调用代码时,我依赖它失败。 (创建Generated
实例的相关反射代码)
异常消息如下所示:(更改名称以匹配示例代码,是的,它的程序集版本是 0.0.0.0)
System.TypeLoadException: Method 'SomeMethod' in type 'SomeNameSpace.Generated' from assembly 'SomeNameSpace.Generated, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
at System.Reflection.RuntimeAssembly.GetType(RuntimeAssembly assembly, String name, Boolean throwOnError, Boolean ignoreCase, ObjectHandleOnStack type)
at System.Reflection.RuntimeAssembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase)
at SomeMoreOfOurOwn.CallingTheReflection.AndFailing(Factory factory)
如前所述,在这种情况下,尝试相同的事情并希望获得不同的结果是可行的,因为这个问题不会在一半时间发生。 (并不是因为代码没有被调用,代码库是基于这种模式构建的 everything)
唯一可预测的是它总是在同一件事上失败,但我认为这只是因为它在所有未更新的生成文件中确定性地首先做那件事。
这是一个 .NET Framework 4.7.1 项目。
我们找到了一名嫌疑人。显然,我们还通过 AssemblyResolve
通过反射加载 Base
的 DLL 使用的 DLL,当版本不匹配时可能会导致此问题,因为它也被另一个直接引用的程序集直接引用,并且 Generated
DLL,也是用Assembly.LoadFrom
加载的。 (顺便说一下,使用 Assembly.Load
没有任何效果。)
我们只是得到了这件事的初步证据,但这是我们最好的预感。
所以总而言之,避免做我们在项目中正在做的任何事情。
在我的项目中,有一个带有抽象方法的抽象基class。
我们基于模式生成实现,然后使用 Assembly.LoadFrom
通过反射加载这些实现,然后调用 Assembly.GetType
以获得在另一个 DLL 中定义的接口的具体实现。
不同项目的结构(DLL文件):
Schema
- 包含类型定义Base
- 具有由所有生成的实现共享的基础 classGenerated
- 生成的类型实现了Base
的抽象基础 class 和Schema
. 的接口
public interface IExample
{
//Some methods here, irrelevant to the problem
}
public abstract Base
{
protected abstract void SomeMethod(SomeType someArg); //This method is the method the exception specifies, but I suspect it's only because it's the first one in the file.
//More methods like the above, and some non-abstract/virtual methods too
}
public class Generated : Base, IExample
{
protected override void SomeMethod(SomeType someArg)
{
//Some implementation here
}
//More content here, not all of it being from either the interface or the Base type
}
var asm = Assembly.LoadFrom(path);
asm.GetType("SomeNameSpace.Generated"); //This is where it fails
在 Base 项目在不相关的区域更新并且它的版本升级之前,这工作正常。
它实现的接口类型正在请求生成的实现。 (类型定义中涉及泛型,不确定是否真的相关)
现在通常这将是一个简单的情况,“哦,您只需要重新编译它并再次包含它”,但令人兴奋的部分是这只是 有时 失败!
大约一半的时间,它都能正常工作。另一半,它抛出 TypeLoadException,认为该方法没有实现。 通常我希望它总是失败,但事实并非如此。
当然,包括新编译生成的 DLL 完全避免了这种情况。但我希望能够在不需要整个项目的情况下更新架构和基础项目。 (仅包含相关文件的 'service pack' 样式软件更新)
需要说明的是,none 涉及的类型已修改。没有“哦,我只是向方法添加了一个可选参数,所以它是相同的方法”错误。
唯一的变化是文件的其他部分。 Base
在一个大的 DLL 中,里面有很多不相关的实用程序。 Base
、IExample
和结果 Generated
仍然完全相同。如果是某些版本解析造成了破坏,我预计会出现问题。
遗憾的是,这不是一个简单的小项目,我可以打包成一个可重现的示例,而是一个具有许多层和模式的相当复杂的程序。我不确定我是否可以重现这个,当程序开始加载东西和调用代码时,我依赖它失败。 (创建Generated
实例的相关反射代码)
异常消息如下所示:(更改名称以匹配示例代码,是的,它的程序集版本是 0.0.0.0)
System.TypeLoadException: Method 'SomeMethod' in type 'SomeNameSpace.Generated' from assembly 'SomeNameSpace.Generated, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation. at System.Reflection.RuntimeAssembly.GetType(RuntimeAssembly assembly, String name, Boolean throwOnError, Boolean ignoreCase, ObjectHandleOnStack type) at System.Reflection.RuntimeAssembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase) at SomeMoreOfOurOwn.CallingTheReflection.AndFailing(Factory factory)
如前所述,在这种情况下,尝试相同的事情并希望获得不同的结果是可行的,因为这个问题不会在一半时间发生。 (并不是因为代码没有被调用,代码库是基于这种模式构建的 everything)
唯一可预测的是它总是在同一件事上失败,但我认为这只是因为它在所有未更新的生成文件中确定性地首先做那件事。
这是一个 .NET Framework 4.7.1 项目。
我们找到了一名嫌疑人。显然,我们还通过 AssemblyResolve
通过反射加载 Base
的 DLL 使用的 DLL,当版本不匹配时可能会导致此问题,因为它也被另一个直接引用的程序集直接引用,并且 Generated
DLL,也是用Assembly.LoadFrom
加载的。 (顺便说一下,使用 Assembly.Load
没有任何效果。)
我们只是得到了这件事的初步证据,但这是我们最好的预感。
所以总而言之,避免做我们在项目中正在做的任何事情。