TypeLoadException提示“没有实现”,但它已经被实现了。

302

我们的测试机出现了一个非常奇怪的bug。错误信息如下:

System.TypeLoadException: 在程序集 'ActiveViewers (...)' 中,类型 'DummyItem' 中的方法 'SetShort' 没有实现。

我真的不明白为什么会出现这个错误。在 DummyItem 类中确实有 SetShort 方法,而且我甚至重新编译了一个版本,并记录了事件日志,以确保这不是部署或版本问题。奇怪的是,调用代码甚至没有调用 SetShort 方法。


17
我喜欢你与社区分享经验并帮助我们所有人,甚至鼓励我们阅读其他答案,谢谢。遗憾的是,这些建议都对我没用。想知道最终对我起作用的是什么吗?重启Visual Studio。为什么我没有首先尝试这个呢? - Paul McLean
此外,在 VS 2017 15.7 更新后,VS 会提示您重新启动。您可能没有这样做(就像我一样,因为我忘记了开会)。我遇到了大量类似于以下的错误... - Structed
1
只是想补充一下我的看法 - 我在运行MsTest单元测试时遇到了这个问题。被测试的类位于已签名的程序集中。GAC中恰好有该程序集的不同版本。MsTest选择使用GAC中的程序集而不是使用bin文件夹中的程序集,并尝试对其运行测试,这显然是无法正常工作的。解决方案是删除GAC中的程序集。 - tom redfern
@PaulMcLean 这是一个很老的评论,但仍然有效;-) 我在 Windows 进入节能模式后遇到了这个问题。没有更改任何代码。所以这是要尝试的第一件事情。 - Jessica
41个回答

275

注意 - 如果这个答案对你没有帮助,请花点时间向下滚动查看其他人添加的答案。

简短回答

如果您在一个程序集中为接口添加了一个方法,然后在另一个程序集中为实现该接口的类添加了该方法,但是在不引用新版本接口程序集的情况下重新构建了实现程序集,则可能会发生这种情况。

在此情况下,DummyItem 实现了来自另一个程序集的接口。SetShort 方法最近被添加到接口和 DummyItem 中 - 但是包含 DummyItem 的程序集重建时只引用了之前版本的接口程序集。因此,SetShort 方法有效地存在,但是缺少将其与接口中相应方法链接起来的特殊处理。

详细回答

如果您想尝试复制此问题,请按照以下步骤进行:

  1. 创建一个类库项目:InterfaceDef,仅添加一个类,并构建:

    public interface IInterface
    {
        string GetString(string key);
        //short GetShort(string key);
    }
    
    创建第二个类库项目:Implementation(单独的解决方案),将InterfaceDef.dll复制到项目目录中并作为文件引用添加,只添加一个类,并构建:
  2. public class ImplementingClass : IInterface
    {
        #region IInterface Members
        public string GetString(string key)
        {
            return "hello world";
        }
    
        //public short GetShort(string key)
        //{
        //    return 1;
        //}
        #endregion
    }
    
  3. 创建第三个控制台项目:ClientCode,在项目目录中复制这两个dll文件,添加文件引用,并将以下代码添加到Main方法中:

  4.  IInterface test = new ImplementingClass();
     string s = test.GetString("dummykey");
     Console.WriteLine(s);
     Console.ReadKey();
    
  5. 运行代码一次,控制台输出“Hello World”

  6. 取消注释两个dll项目中的代码并重新构建——将两个dll复制回ClientCode项目中,重新构建并尝试再次运行。尝试实例化ImplementingClass时出现TypeLoadException。


1
您可能需要添加控制台应用程序应使用新的 DLL 作为引用进行重建。仅复制 DLL 是行不通的,这可能是由于版本不匹配(即在编译源 DLL 后,版本会更改)。这个理解是否公平? - shahkalpesh
5
嗯,看起来微软的错误信息出现了错误——它说一个名为“DummyItem”的类的某个方法没有实现,这显然是错误的……实际上问题是该接口的某个方法未被“DummyItem”类实现。 - Qwertie
3
有没有关于这个问题的好的最终解决方案?微软推荐了什么解决方案? - Kiquenet
21
解决方法是手动删除 bin 文件。由于发布程序没有将其视为已更改的文件,因此您需要强制它使用最新的文件。这个真的应该在排名第一的答案中注明! - DJ.
1
在我的情况下,我将程序集打包为NuGet包,并在使用这些包的另一个项目中遇到了错误。我尝试删除bin文件,但没有成功,然后我删除了有问题的代码,重新打包,然后成功了。之后,我再次尝试包含有问题的代码,又成功了。 - Kubra
显示剩余9条评论

38

除了提问者自己的答案已经说明的内容外,可能值得注意的是以下内容。发生这种情况的原因是因为一个类可以拥有与接口方法相同签名的方法,而不实现该方法。下面的代码说明了这一点:

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

这对我解决了问题,并增加了混淆的程度,它声称缺少的方法是在父类实现的接口中声明的,并在子类中再次声明。从子类中删除重复内容使错误消失了。 - ilikeprogramming

26

当我的应用程序没有引用另一个定义了错误消息中使用的类的程序集时,我得到了这个错误。运行PEVerify可以得到更有用的错误信息:“系统找不到指定的文件。”


24

我看到了同样的消息,以下是我们发现的情况:

我们的项目中使用了第三方dll。在新版本的dll发布后,我们将项目指向新的dll集并成功编译。

当我尝试在运行时实例化其中一个接口类时,就抛出了异常。我们确保所有其他引用都是最新的,但仍然没有好运。

我们需要一段时间来利用“对象浏览器”找出问题所在,错误消息中方法的返回类型是新的、未引用程序集中的全新类型。

我们添加了对该程序集的引用,错误消失了。

  • 错误消息相当误导人,但指向了大致正确的方向(正确的方法,错误的消息)。
  • 即使我们没有使用相关方法,异常也会发生。
  • 这让我产生了一个问题:如果无论什么情况下都会抛出这个异常,为什么编译器不会捕捉到它呢?

20

在以下情况下出现了这个错误:

  • 程序集 A 和 B 都引用了 System.Web.Mvc 版本 3.0.0.0
  • 程序集 A 引用了程序集 B,并且其中的类实现了来自程序集 B 的接口,这些接口中的方法返回了 System.Web.Mvc 中的类。
  • 程序集 A 升级到了 System.Web.Mvc 版本 4.0.0.0
  • 程序集 C 运行了下面的代码(FertPin.Classes.Contact 包含在程序集 A 中):

var target = Assembly.GetAssembly(typeof(FertPin.Classes.Contact));

对我而言,解决方法是将程序集 B 中的 System.Web.Mvc 引用升级到 4.0.0.0 版本。现在看起来很显然!

感谢原帖作者!


我曾经遇到一个类似的问题,但与版本有关。其中一种方法是针对.NET 2,它返回了来自v2的System.Windows.Forms类型。在.NET 4目标程序集中重写实现返回了相同的类型,但来自于v4的System.Windows.Forms。编译通过了,但ReflectionOnlyLoadFrom不喜欢它。 - Stephen Hewlett
我曾经遇到过类似的问题,这是由于将针对.NET2的类型加载到.NET4应用程序的ReflectionOnly上下文中所致。我通过在AppDomain.ReflectionOnlyAssemblyResolve事件中将所有.NET2核心程序集的装配请求重定向到它们的.NET4对应项来解决了这个问题。 - Chaquotay

14
另一种出现此错误的情况是您拥有签名程序集的错误版本。这不是此原因的正常症状,但以下是我遇到此错误的场景:
  • 一个asp.net项目包含程序集A和程序集B,其中B是强命名的。

  • 程序集A使用Activator.CreateInstance来加载程序集C(即没有对分别构建的C进行引用)。

  • C是使用旧版本的程序集B构建的,而当前存在的版本不同。

希望能对某人有所帮助 - 我花了很长时间才弄清楚这一点。

如果部署脚本复制了旧的DLL,就会发生这种情况,例如在同一组输出文件夹中编译多个版本时。 - Suncat2000
更多细节:我添加了一个新项目并在后来的版本中扩展了一个接口,然后进行了构建。我切换到早期版本并进行了构建。 "new"文件夹仍然存在,并且通过外部脚本将具有修改接口的DLL从“unversioned”文件夹复制到新构建中。我的错误是在共同的检出文件夹中构建。我通过在Windows资源管理器中搜索文件夹找到了它; 它在当前构建的一部分之外的文件夹中。 - Suncat2000

10

我一直回到这个问题...... 这里的许多答案很好地解释了问题出在哪里,但没有说明如何解决。

解决方法是手动删除项目发布目录中的bin文件。这将清理所有引用并强制项目使用最新的DLL。

我不建议使用发布工具的删除功能,因为这往往会使IIS出现问题。


我在一个非 Web 项目中也发现了这种情况 - 我正在反射一个程序集到另一个程序集中(使用 LoadFile),清理和重建并没有起作用 - 删除两个项目的 bin 文件夹中的所有文件确实起了作用。感谢您的建议! - d219
我不得不进行IIS重置,因为这个特定的项目在本地使用IIS(不幸的是)。 - Tim Wilson

10

我也遇到过这个错误,它是由一个Any CPU exe引用了另一个引用了x86程序集的Any CPU程序集导致的。

异常抱怨在MyApp.Implementations(Any CPU)类中的一个方法,该类派生自MyApp.Interfaces(Any CPU),但在fuslogvw.exe中,我发现了一个隐藏的“尝试使用不正确格式加载程序”的异常,来自于两者都使用的MyApp.CommonTypes(x86)。


7
在使用Autofac和大量动态装配加载的情况下,我遇到了这个错误。在执行Autofac解析操作时,运行时将无法加载其中一个程序集。错误消息抱怨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>

我可以问一下你是怎么发现的吗?你使用了任何非标准的调试技术吗?我也遇到了同样的错误,但我认为它是由于不同的dll引起的,因为我已经为不可变量进行了绑定重定向。 - t3chb0t
1
嗯,那是一段时间以前的事了。我想主要线索是“未实现”方法的参数使用了System.Collections.Immutable中的类型。在我的情况下,受影响的方法中没有太多其他候选参数或返回类型。我还记得使用ILSpy检查编译的“DefinitionAssembly”和“ImplementationAssembly”DLL中的依赖元数据,特别是参考文献的版本。 - Hydrargyrum
1
非常感谢!;-) 我在Visual Studio中安装了ILSpy扩展,并查看了参考分支,其中有一个用于System.Net.Http包的引用,我为它添加了dependentAssembly元素,并从ILSpy复制了信息,现在它可以正常工作了,错误已经消失了! - t3chb0t
我通过将以下代码放入程序中并在其后设置断点以查看值,发现了哪个是有问题的GAC程序集,并且发现已加载了两个版本的System.Net.Http:var loadedAssemblies = from a in AppDomain.CurrentDomain.GetAssemblies() orderby a.FullName select (a.FullName, a); - paulie4

6
我有一个神秘的解决方法来解决这个错误信息。我将目标框架从.Net 4.0升级到了4.6,然后在构建时,我的单元测试项目给出了“System.TypeLoadException...没有实现”的错误。它还给出了另一个关于同样未实现方法的错误消息,该消息说:“'BuildShadowTask'任务意外失败。”这里的任何建议都没有帮助,所以我搜索了“BuildShadowTask”,并找到了MSDN上的一篇文章,它指导我使用文本编辑器从单元测试项目的csproj文件中删除这些行。
<ItemGroup>
  <Shadow Include="Test References\MyProject.accessor" />
</ItemGroup>

之后这两个错误都消失了,项目构建成功。


这对我来说是答案。我在从.NET 4.5升级到4.6后遇到了这个错误。 - twblamer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接