我们的测试机出现了一个非常奇怪的bug。错误信息如下:
System.TypeLoadException: 在程序集 'ActiveViewers (...)' 中,类型 'DummyItem' 中的方法 'SetShort' 没有实现。
我真的不明白为什么会出现这个错误。在 DummyItem
类中确实有 SetShort
方法,而且我甚至重新编译了一个版本,并记录了事件日志,以确保这不是部署或版本问题。奇怪的是,调用代码甚至没有调用 SetShort
方法。
我们的测试机出现了一个非常奇怪的bug。错误信息如下:
System.TypeLoadException: 在程序集 'ActiveViewers (...)' 中,类型 'DummyItem' 中的方法 'SetShort' 没有实现。
我真的不明白为什么会出现这个错误。在 DummyItem
类中确实有 SetShort
方法,而且我甚至重新编译了一个版本,并记录了事件日志,以确保这不是部署或版本问题。奇怪的是,调用代码甚至没有调用 SetShort
方法。
注意 - 如果这个答案对你没有帮助,请花点时间向下滚动查看其他人添加的答案。
简短回答
如果您在一个程序集中为接口添加了一个方法,然后在另一个程序集中为实现该接口的类添加了该方法,但是在不引用新版本接口程序集的情况下重新构建了实现程序集,则可能会发生这种情况。
在此情况下,DummyItem 实现了来自另一个程序集的接口。SetShort 方法最近被添加到接口和 DummyItem 中 - 但是包含 DummyItem 的程序集重建时只引用了之前版本的接口程序集。因此,SetShort 方法有效地存在,但是缺少将其与接口中相应方法链接起来的特殊处理。
详细回答
如果您想尝试复制此问题,请按照以下步骤进行:
创建一个类库项目:InterfaceDef,仅添加一个类,并构建:
public interface IInterface
{
string GetString(string key);
//short GetShort(string key);
}
创建第二个类库项目:Implementation(单独的解决方案),将InterfaceDef.dll复制到项目目录中并作为文件引用添加,只添加一个类,并构建:public class ImplementingClass : IInterface
{
#region IInterface Members
public string GetString(string key)
{
return "hello world";
}
//public short GetShort(string key)
//{
// return 1;
//}
#endregion
}
创建第三个控制台项目:ClientCode,在项目目录中复制这两个dll文件,添加文件引用,并将以下代码添加到Main方法中:
IInterface test = new ImplementingClass();
string s = test.GetString("dummykey");
Console.WriteLine(s);
Console.ReadKey();
运行代码一次,控制台输出“Hello World”
取消注释两个dll项目中的代码并重新构建——将两个dll复制回ClientCode项目中,重新构建并尝试再次运行。尝试实例化ImplementingClass时出现TypeLoadException。
除了提问者自己的答案已经说明的内容外,可能值得注意的是以下内容。发生这种情况的原因是因为一个类可以拥有与接口方法相同签名的方法,而不实现该方法。下面的代码说明了这一点:
public interface IFoo
{
void DoFoo();
}
public class Foo : IFoo
{
public void DoFoo() { Console.WriteLine("This is _not_ the interface method."); }
void IFoo.DoFoo() { Console.WriteLine("This _is_ the interface method."); }
}
Foo foo = new Foo();
foo.DoFoo(); // This calls the non-interface method
IFoo foo2 = foo;
foo2.DoFoo(); // This calls the interface method
当我的应用程序没有引用另一个定义了错误消息中使用的类的程序集时,我得到了这个错误。运行PEVerify可以得到更有用的错误信息:“系统找不到指定的文件。”
我看到了同样的消息,以下是我们发现的情况:
我们的项目中使用了第三方dll。在新版本的dll发布后,我们将项目指向新的dll集并成功编译。
当我尝试在运行时实例化其中一个接口类时,就抛出了异常。我们确保所有其他引用都是最新的,但仍然没有好运。
我们需要一段时间来利用“对象浏览器”找出问题所在,错误消息中方法的返回类型是新的、未引用程序集中的全新类型。
我们添加了对该程序集的引用,错误消失了。
在以下情况下出现了这个错误:
var target = Assembly.GetAssembly(typeof(FertPin.Classes.Contact));
对我而言,解决方法是将程序集 B 中的 System.Web.Mvc 引用升级到 4.0.0.0 版本。现在看起来很显然!
感谢原帖作者!
一个asp.net项目包含程序集A和程序集B,其中B是强命名的。
程序集A使用Activator.CreateInstance来加载程序集C(即没有对分别构建的C进行引用)。
C是使用旧版本的程序集B构建的,而当前存在的版本不同。
我一直回到这个问题...... 这里的许多答案很好地解释了问题出在哪里,但没有说明如何解决。
解决方法是手动删除项目发布目录中的bin文件。这将清理所有引用并强制项目使用最新的DLL。
我不建议使用发布工具的删除功能,因为这往往会使IIS出现问题。
我也遇到过这个错误,它是由一个Any CPU exe引用了另一个引用了x86程序集的Any CPU程序集导致的。
异常抱怨在MyApp.Implementations(Any CPU)类中的一个方法,该类派生自MyApp.Interfaces(Any CPU),但在fuslogvw.exe中,我发现了一个隐藏的“尝试使用不正确格式加载程序”的异常,来自于两者都使用的MyApp.CommonTypes(x86)。
ImplementationAssembly
中的MyType
类型中的MyMethod
方法没有实现。这种情况发生在Windows Server 2012 R2 VM上运行时出现,但在Windows 10或Windows Server 2016 VM上没有出现。
ImplementationAssembly
引用了System.Collections.Immutable
1.1.37,并包含IMyInterface<T1,T2>
接口的实现,该接口定义在单独的DefinitionAssembly
中。 DefinitionAssembly
引用了System.Collections.Immutable
1.1.36。
IMyInterface<T1,T2>
中的“未实现”方法具有IImmutableDictionary<TKey, TRow>
类型的参数,该参数在System.Collections.Immutable
中定义。System.Collections.Immutable
的实际副本是版本1.1.37。在我的Windows Server 2012 R2 VM上,GAC包含了System.Collections.Immutable
1.1.36的副本。在Windows 10和Windows Server 2016上,GAC包含了System.Collections.Immutable
1.1.37的副本。只有当GAC包含旧版本的DLL时,才会发生加载错误。System.Collections.Immutable
的引用不匹配。接口定义和实现具有相同的方法签名,但实际上依赖于不同版本的System.Collections.Immutable
,这意味着运行时不认为实现类与接口定义相匹配。<dependentAssembly>
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.1.37.0" newVersion="1.1.37.0" />
</dependentAssembly>
System.Collections.Immutable
中的类型。在我的情况下,受影响的方法中没有太多其他候选参数或返回类型。我还记得使用ILSpy检查编译的“DefinitionAssembly”和“ImplementationAssembly”DLL中的依赖元数据,特别是参考文献的版本。 - HydrargyrumSystem.Net.Http
包的引用,我为它添加了dependentAssembly
元素,并从ILSpy复制了信息,现在它可以正常工作了,错误已经消失了! - t3chb0t<ItemGroup>
<Shadow Include="Test References\MyProject.accessor" />
</ItemGroup>
之后这两个错误都消失了,项目构建成功。