关于c#:TypeLoadException表示“没有实现”,但它已实现

TypeLoadException says 'no implementation', but it is implemented

我们的测试机上有一个非常奇怪的错误。错误是:

System.TypeLoadException: Method 'SetShort' in type 'DummyItem' from assembly 'ActiveViewers (...)' does not have an implementation.

我就是不明白为什么。SetShort存在于DummyItem类中,我甚至重新编译了一个版本,并将其写入事件日志,以确保它不是部署/版本控制问题。奇怪的是,调用代码甚至没有调用SetShort方法。


注意-如果这个答案对你没有帮助,请花点时间向下滚动浏览人们从那以后添加的其他答案。

简短回答

如果将方法添加到一个程序集中的接口,然后添加到另一个程序集中的实现类,则可能发生这种情况,但您可以在不引用接口程序集的新版本的情况下重新生成实现程序集。

在这种情况下,dummyItem实现来自另一个程序集的接口。setshort方法最近被添加到接口和dummyItem中,但是包含dummyItem的程序集是参照以前版本的接口程序集重新生成的。因此,setshort方法是有效的,但没有将其与界面中的等效方法相联系的魔力酱汁。

长回答

如果要尝试复制此内容,请尝试以下操作:

  • 创建类库项目:interfacedef,只添加一个类,然后生成:

    1
    2
    3
    4
    5
    public interface IInterface
    {
        string GetString(string key);
        //short GetShort(string key);
    }
  • 创建第二个类库项目:实现(使用单独的解决方案),将interfacedef.dll复制到项目目录并添加为文件引用,只添加一个类,然后生成:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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复制到项目目录中,添加文件引用,并将以下代码添加到主方法中:

    1
    2
    3
    4
     IInterface test = new ImplementingClass();
     string s = test.GetString("dummykey");
     Console.WriteLine(s);
     Console.ReadKey();
  • 运行代码一次,控制台说"你好,世界"

  • 取消对两个dll项目中的代码的注释并重新生成-将两个dll复制回clientcode项目,重新生成并再次尝试运行。尝试实例化ImplementingClass时发生TypeLoadException。


  • 除了提问者自己的回答已经陈述的内容之外,可能还需要注意以下内容。发生这种情况的原因是,一个类有可能在不实现该方法的情况下拥有与接口方法具有相同签名的方法。以下代码说明:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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集并成功编译。

    当我试图在运行时实例化它们的接口类之一时,引发了异常。我们确保所有其他推荐信都是最新的,但仍然没有运气。我们需要一段时间来发现(使用对象浏览器)错误消息中方法的返回类型是来自新的未引用程序集的全新类型。

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

    • 错误消息相当误导,但或多或少指向了正确的方向(正确的方法、错误的消息)。
    • 即使我们没有使用有问题的方法,也会发生异常。
    • 这就引出了一个问题:如果在任何情况下抛出了这个异常,为什么编译器都不接受它?


    在下面的场景中,我收到了这个错误。

    • 程序集A和B都引用了System.Web.MVC版本3.0.0.0
    • 程序集A引用了程序集B,并具有使用从System.Web.MVC返回类的方法实现程序集B接口的类。
    • 程序集A升级到System.Web.MVC版本4.0.0.0
    • 程序集C运行以下代码(程序集A中包含fertpin.classes.contact):

    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的旧版本比当前的版本要旧

    希望能帮助别人-我花了很多时间才弄明白。


    我也有这个错误,它是由一个引用任何CPU程序集的任何CPU exe引起的,而该CPU程序集又引用了一个x86程序集。

    该异常抱怨myapp.implementations(any cpu)中某个类的方法,该类派生了myapp.interfaces(any cpu),但在fuslogvw.exe中,我发现了myapp.commontypes(x86)中的一个隐藏的"尝试加载格式不正确的程序"异常,这两个类都使用该异常。


    我一直在想…这里的许多答案都很好地解释了问题是什么,而不是如何解决问题。

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

    我不建议使用发布工具删除功能,因为这会引发IIS。


    我在使用autopac和大量动态程序集加载的上下文中遇到了这个错误。

    执行自动AC解析操作时,运行时将无法加载其中一个程序集。错误消息抱怨Method 'MyMethod' in type 'MyType' from assembly 'ImplementationAssembly' does not have an implementation。在Windows Server 2012 R2虚拟机上运行时出现症状,但在Windows 10或Windows Server 2016虚拟机上没有出现症状。

    ImplementationAssembly引用System.Collections.Immutable1.1.37,包含IMyInterface接口的实现,该接口在单独的DefinitionAssembly中定义。DefinitionAssembly参考System.Collections.Immutable1.1.36。

    IMyInterface中"未实现"的方法具有IImmutableDictionary类型的参数,在System.Collections.Immutable中定义。

    在程序目录中找到的System.Collections.Immutable的实际副本是版本1.1.37。在我的WindowsServer2012 r2 vm上,GAC包含一个System.Collections.Immutable1.1.36的副本。在Windows 10和Windows Server 2016上,GAC包含一份System.Collections.Immutable1.1.37的副本。加载错误仅在GAC包含旧版本的DLL时发生。

    因此,装配负载失败的根本原因是对System.Collections.Immutable的引用不匹配。接口定义和实现具有相同的外观方法签名,但实际上依赖于不同版本的System.Collections.Immutable,这意味着运行时没有考虑实现类来匹配接口定义。

    添加以下绑定重定向到我的应用程序配置文件修复了此问题:

    1
    2
    3
    4
    <dependentAssembly>
           
            <bindingRedirect oldVersion="0.0.0.0-1.1.37.0" newVersion="1.1.37.0" />
    </dependentAssembly>


    对于这个错误消息,我还有另一个深奥的解决方案。我将目标框架从.NET 4.0升级到了4.6,我的单元测试项目在我尝试构建时给了我"System.TypeLoadException…Not have an implementation"错误。它还给出了第二条错误消息,关于"buildshadowtask"任务意外失败的假定未实现方法。这里的建议似乎都没有帮助,所以我搜索了"buildshadowtask",并在msdn上找到了一个帖子,这导致我使用文本编辑器从单元测试项目的csproj文件中删除这些行。

    1
    2
    3
    <ItemGroup>
      <Shadow Include="Test References\MyProject.accessor" />
    </ItemGroup>

    在那之后,两个错误都消失了,项目也建立了。


    我得到了一个"钻石"形状的项目依赖关系:

    • 项目A使用项目B和项目D
    • 项目B使用项目D

    我重新编译了项目A,但没有重新编译项目B,这使得项目B可以"注入"项目D DLL的旧版本。


    我在重命名一个项目(和程序集名称)时遇到了这个问题,该项目依赖于一个ASP.NET项目。Web项目中的类型在依赖程序集中实现了接口。尽管从build菜单执行了clean solution,但具有以前名称的程序集仍保留在bin文件夹中,并且在执行我的Web项目时

    1
    2
    3
    4
    5
    var types = AppDomain.CurrentDomain.
       GetAssemblies().
       ToList().
       SelectMany( s => s.GetTypes() /* exception thrown in this call */ )
    ;

    引发了上述异常,抱怨实现Web类型中的接口方法实际上没有实现。手动删除Web项目的bin文件夹中的程序集解决了该问题。


    当我以前在其中一个程序集的单元测试期间启用了代码覆盖率时,我也得到了这个错误。出于某种原因,Visual Studio"缓冲"了此特定dll的旧版本,即使我已将其更新以实现接口的新版本。禁用代码覆盖率消除了错误。


    如果使用assembly.loadfrom(string)加载程序集,并且引用的程序集已使用assembly.load(byte[])加载,也可能会导致此错误。

    例如,您已经将主应用程序的引用程序集嵌入为资源,但您的应用程序从特定文件夹加载插件。

    不要使用loadfrom,应该使用load。以下代码将完成此项工作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    private static Assembly LoadAssemblyFromFile( String filePath )
    {
        using( Stream stream = File.OpenRead( filePath ) )
        {
            if( !ReferenceEquals( stream, null ) )
            {
                Byte[] assemblyData = new Byte[stream.Length];
                stream.Read( assemblyData, 0, assemblyData.Length );
                return Assembly.Load( assemblyData );
            }
        }
        return null;
    }


    我刚将一个解决方案从MVC3升级到MVC5,并开始从我的单元测试项目接收到相同的异常。

    检查了所有寻找旧文件的引用后,偶然发现我需要在我的单元测试项目中为MVC做一些绑定目录。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <runtime>
       
          <dependentAssembly>
           
            <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
          </dependentAssembly>
          <dependentAssembly>
           
            <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
          </dependentAssembly>
          <dependentAssembly>
           
            <bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
          </dependentAssembly>
        </assemblyBinding>
      </runtime>
    </configuration>

    在我的例子中,它帮助重置WinForms工具箱。

    我在设计器中打开Form时遇到了异常;但是,编译和运行代码是可能的,代码的行为与预期的一样。异常发生在从我的一个引用库实现接口的本地UserControl中。此库更新后出现错误。

    这个UserControl列在winforms工具箱中。可能是Visual Studio在库的过时版本上保留了一个引用,或者在某处缓存了一个过时的版本。

    以下是我如何从这种情况中恢复过来:

  • 右键单击WinForms工具箱,然后单击上下文菜单中的Reset Toolbox。(这将从工具箱中删除自定义项)。在我的例子中,工具箱项被恢复到默认状态;但是,工具箱中缺少指针箭头。
  • 关闭Visual Studio。在我的例子中,Visual Studio以一个冲突异常终止并中止。
  • 重新启动Visual Studio。现在一切顺利。

  • fwiw,当有一个配置文件重定向到不存在的引用程序集版本时,我得到了这个。为胜利记录融合!


    对涉及托管C++的这类问题的另一种解释。

    如果您试图截断在使用具有特殊签名的托管C++创建的程序集中定义的接口,则在创建存根时将获得异常。

    这对于犀牛模型和任何使用System.Reflection.Emit的模拟框架都是正确的。

    1
    2
    3
    4
    5
    6
    7
    8
    public interface class IFoo {
      void F(long bar);
    };

    public ref class Foo : public IFoo {
    public:
      virtual void F(long bar) { ... }
    };

    接口定义获取以下签名:

    1
    void F(System.Int32 modopt(IsLong) bar)

    请注意,C++类型EDCOX1的1个图映射到EDCOX1×2(或简单的EcOcx1·3)。正如犀牛嘲弄邮件列表中的AyendeRahien所说,正是有点模糊的modopt导致了这个问题。


    在我的例子中,我以前引用过回购之外的兄弟文件夹中的一个mylib项目,我们称之为v1.0

    1
    2
    3
    4
    5
    |-- myrepo
    |    |-- consoleApp
    |    |-- submodules
    |         |-- mylib (submoduled v2.0)
    |-- mylib (stale v1.0)

    后来我做得很好,通过git子模块使用它,我们称之为v2.0。但有一个项目consoleApp没有正确更新。它仍然引用了我的Git项目之外的旧的v1.0项目。

    令人困惑的是,尽管*.csproj显然是错误的,并且指向v1.0,但Visual Studio IDE将路径显示为v2.0项目!为了检查接口和类,F12也进入了v2.0版本。

    编译器放在bin文件夹中的程序集是v1.0版本,因此比较麻烦。

    IDE对我撒谎的事实让我很难意识到这个错误。

    解决方案:从consoleApp中删除项目引用,并对其进行读写。

    一般提示:从头重新编译所有程序集(在可能的情况下,当然不能用于nuget包),并检查bin\debug文件夹中的日期时间戳。任何旧的集会都是你的问题。


    我得到这个错误是因为我在框架的4.5版本的程序集"c"中有一个类,在框架的4.5.1版本的程序集"a"中实现了一个接口,并且作为程序集"b"的基类,而程序集"b"也在框架的4.5.1版本中。系统在尝试加载程序集"b"时引发异常。此外,我在所有三个程序集上都安装了一些面向.NET 4.5.1的nuget包。出于某种原因,尽管nuget引用没有显示在程序集"b"中,但它正在成功生成。

    事实证明,真正的问题是程序集引用了包含接口的nuget包的不同版本,而接口签名在不同版本之间发生了更改。


    我面临着几乎相同的问题。我抓了抓头,是什么导致了这个错误。我进行了交叉检查,所有的方法都实现了。

    在谷歌上,我得到了这个链接。基于@paul mclink的评论,这两个步骤解决了这个问题。

  • 重新启动Visual Studio
  • 清理、建造(重建)
  • 错误消失了。

    重新启动vs插件

    谢谢保罗:

    希望这能帮助遇到此错误的人:)


    我在一个wcf服务中得到这个,因为选择了一个x86构建类型,导致bin位于binx86而不是bin下。选择任何CPU都会导致重新编译的DLL转到正确的位置(我不会首先详细介绍这是如何发生的)。


    我在Visual Studio Pro 2008中看到了这一点,当时两个项目生成了同名的程序集,一个是类lib sdf.dll,另一个是引用程序集名称为sdf.exe的lib。当我更改引用程序集的名称时,异常消失了。


    我在运行单元测试时也遇到了这个问题。应用程序运行良好,没有错误。在我的案例中,问题的原因是我关闭了测试项目的构建。重新建立我的测试项目解决了问题。


    这是我对这个错误的看法。

    添加了一个extern方法,但我的粘贴有问题。江户十一号〔六号〕被挂上了一条评论线。

    1
    2
    3
    /// <returns>(removed for brevity lol)</returns>[DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool IsWindowVisible(IntPtr hWnd);

    确保该属性实际包含在源中,修复了该问题。


    我今天收到这个错误。我的问题是-不要在tfs中执行获取最新版本。在服务器中有一个带有接口的dll,其中一个方法已被修改。我和一个老家伙一起工作——在我的电脑里。如何修复:获取最新信息,重建


    我在最近的Windows更新后收到此错误。我将服务类设置为从接口继承。接口包含一个返回valuetuple的签名,这是C中一个相当新的功能。

    我只能猜测,Windows Update安装了一个新的,但甚至显式引用它,更新绑定重定向等…最终结果只是将方法的签名更改为"标准",我想你可以这么说。


    在我的例子中,我试图使用TypeBuilder创建一个类型。TypeBuilder.CreateType提出了这个例外。我最终意识到,在为一个帮助实现接口的方法调用TypeBuilder.DefineMethod时,我需要将MethodAttributes.Virtual添加到属性中。这是因为如果没有此标志,该方法不会实现接口,而是使用相同的签名(即使没有指定MethodAttributes.NewSlot)来实现新方法。


    我也有同样的问题。我发现我的程序集(由主程序加载)有一些引用,其中"copy local"设置为true。这些引用的本地副本正在同一文件夹中查找其他引用,但该文件夹不存在,因为其他引用的"复制本地"设置为false。删除"意外"复制的引用后,由于主程序被设置为查找引用的正确位置,因此错误消失。显然,引用的本地副本破坏了调用的顺序,因为这些本地副本被使用,而不是主程序中的原始副本。

    take home消息是由于缺少加载所需程序集的链接而出现此错误。


    这就意味着在我的案例中,实现项目已经过时了。包含接口的dll已重建,但实现dll已过时。


    作为补充:如果您更新了一个用于生成仿冒组件的nuget包,也可能发生这种情况。假设您安装了一个nuget包的v1.0版,并创建了一个fakelibrary.1.0.0.0.fakes程序集。接下来,更新到nuget包的最新版本,比如v1.1,它向接口添加了一个新方法。Fakes库仍在寻找v1.0版本的库。只需移除假组件并重新生成。如果这是问题所在,这可能会解决。


    我们的问题通过更新窗口解决了!我们的Web应用程序在.NET 4.7.1和C_7.0上。当我们在不同的窗口中进行测试时,我们知道通过更新窗口可以解决这个问题。事实上,这个问题出现在Windows10(1703版)和WindowsServer2012(去年没有更新)中。在更新了这两个版本之后,问题就解决了。实际上,ASP.NET次要版本(C:windowsmicrosoft.netframework64v4.0.30319中clr.dll版本的第三部分)在更新后发生了一些更改。


    我解决这个问题的是CleanRebuildSolution


    只是补充一下我的经验,因为其他答案中没有涉及到:

    我在MSTEST中运行单元测试时遇到这个问题。

    测试中的类在签名的程序集中。

    此程序集的另一个版本碰巧位于GAC中(但具有相同的程序集版本号)。

    强名称程序集的依赖项解析算法与未签名程序集稍有不同,因为首先检查GAC。

    所以MSTEST选择了GAC的程序集,而不是使用bin文件夹中的程序集,并尝试对其运行测试,这显然不起作用。

    解决方案是移除GAC的组件。

    注意,我的线索是,当测试运行时,生成服务器上没有发生这种情况,因为该生成将使用新的程序集版本号编译程序集。这意味着GAC中的旧版本的程序集将无法使用。

    此外,我在这里发现了一个潜在的解决方案,如果您由于某种原因无法访问GAC:https://johanleino.wordpress.com/2014/02/20/workaround-for-unit-testing-code-that-losters-in-the-gac/


    我遇到了这个问题,只有我的本地机器出了问题。我们组和我的虚拟机中没有其他开发人员有这个问题。

    最后,它似乎与"目标群体"有关。Visual Studio 2017年

    • 打开Visual Studio安装程序
    • 选择修改
    • 转到第二个顶部选项卡"单个组件"
    • 查看您选择的框架和目标包。
    • 我没有选择两个最新的目标包
    • 我还注意到我没有选择"高级ASP.NET功能",其他机器也没有。
    • 选择并安装了新项目,现在一切正常。

    另一种方法是:

    1
    2
    3
    class GenericFoo<T> {}

    class ConcreteFoo : GenericFoo<ClassFromAnotherAssembly> {}

    程序集中不引用ClassFromAnotherAssembly程序集的代码。

    1
    var foo = new ConcreteFoo(); //kaboom

    当classfromanotherassembly为valuetuple时发生了这种情况。


    另一种可能性是在依赖项中混合使用发布和调试构建。例如,程序集A依赖于程序集B,A在调试模式下生成,而B在GAC中的副本在发布模式下生成,反之亦然。