TypeLoadException 表示“没有实现”,但它已实现

发布于 2024-12-15 17:36:41 字数 287 浏览 4 评论 0 原文

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

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

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

I've got a very weird bug on our test machine. The error is:

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

I just can't understand why. SetShort is there in the DummyItem class, and I've even recompiled a version with writes to the event log just to make sure that it's not a deployment/versioning issue. The weird thing is that the calling code doesn't even call the SetShort method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

绾颜 2024-12-22 17:36:41

当我之前在其中一个程序集的单元测试期间启用代码覆盖率时,我也遇到了此错误。由于某种原因,Visual Studio“缓冲”了这个特定 DLL 的旧版本,尽管我已经更新了它以实现新版本的接口。禁用代码覆盖率消除了该错误。

I also got this error when I had previously enabled Code Coverage during unit testing for one of the assemblies. For some reason Visual Studio "buffered" the old version of this particular DLL even though I had updated it to implement a new version of the interface. Disabling Code Coverage got rid of the error.

在风中等你 2024-12-22 17:36:41

如果使用 Assembly.LoadFrom(String) 加载程序集并且引用已使用 Assembly.Load(Byte[]) 加载的程序集,也可能会导致此错误。

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

您应该使用 Load,而不是使用 LoadFrom。下面的代码将完成这项工作:

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;
}

This error can also be caused if an assembly is loaded using Assembly.LoadFrom(String) and is referencing an assembly that was already loaded using Assembly.Load(Byte[]).

For instance you have embedded the main application's referenced assemblies as resources but your app loads plug-ins from a specific folder.

Instead of using LoadFrom you should use Load. The following code will do the job:

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;
}
玩世 2024-12-22 17:36:41

FWIW,当有一个配置文件重定向到引用程序集的不存在版本时,我得到了这个。融合日志以取得胜利!

FWIW, I got this when there was a config file that redirected to a non-existent version of a referenced assembly. Fusion logs for the win!

似梦非梦 2024-12-22 17:36:41

我收到此错误是因为我在框架版本 4.5 上的程序集“C”中有一个类,在框架版本 4.5.1 上的程序集“A”中实现了一个接口,并充当程序集的基类“B”也在该框架的 4.5.1 版本中。系统在尝试加载程序集“B”时抛出异常。此外,我还在所有三个程序集上安装了一些针对 .net 4.5.1 的 nuget 包。由于某种原因,即使 nuget 引用没有显示在程序集“B”中,它仍然构建成功。

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

I got this error because I had a class in an assembly 'C' which was on version 4.5 of the framework, implementing an interface in assembly 'A' which was on version 4.5.1 of the framework and serving as the base class to assembly 'B' which was also on version 4.5.1 of the framework. The system threw the exception while trying to load assembly 'B'. Additionally, I had installed some nuget packages targeting .net 4.5.1 on all three assemblies. For some reason, even though the nuget references were not showing in assembly 'B', it was building successfully.

It turned out that the real issue was that the assemblies were referencing different versions of a nuget package that contained the interface and the interface signature had changed between versions.

謌踐踏愛綪 2024-12-22 17:36:41

对于这个错误消息,我还有另一个深奥的解决方案。我将目标框架从 .Net 4.0 升级到 4.6,当我尝试构建时,我的单元测试项目给出了“System.TypeLoadException...没有实现”错误。它还给出了第二条关于相同的所谓未实现方法的错误消息,即“‘BuildShadowTask’任务意外失败。”这里的建议似乎都没有帮助,所以我搜索了“BuildShadowTask”,并找到了 MSDN 上的一篇文章 引导我使用文本编辑器从单元测试项目的 csproj 文件中删除这些行。

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

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

I have yet another esoteric solution to this error message. I upgraded my target framework from .Net 4.0 to 4.6, and my unit test project was giving me the "System.TypeLoadException...does not have an implementation" error when I tried to build. It also gave a second error message about the same supposedly non-implemented method that said "The 'BuildShadowTask' task failed unexpectedly." None of the advice here seemed to help, so I searched for "BuildShadowTask", and found a post on MSDN which led me to use a text editor to delete these lines from the unit test project's csproj file.

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

After that, both errors went away and the project built.

淡看悲欢离合 2024-12-22 17:36:41

当我重命名一个 ASP.NET 项目所依赖的项目(和程序集名称)时,我遇到了这种情况。 Web 项目中的类型实现了依赖程序集中的接口。尽管从 Build 菜单中执行 Clean Solution,但具有先前名称的程序集仍保留在 bin 文件夹中,并且当我的 Web 项目执行时,

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

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

I encountered this when I renamed a project (and the assembly name), which was depended upon by an ASP.NET project. Types in the web project implemented interfaces in the dependent assembly. Despite executing Clean Solution from the Build menu, the assembly with the previous name remained in the bin folder, and when my web project executed

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

the above exception was thrown, complaining that interface methods in the implementing web types were not actually implemented. Manually deleting the assembly in the web project's bin folder resolved the problem.

热血少△年 2024-12-22 17:36:41

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

检查了所有寻找旧文件的参考资料,最终发现我需要在我的单元测试项目中为 Mvc 做一些绑定重定向。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

I just upgraded a solution from MVC3 to MVC5, and started receiving the same exception from my Unit test project.

Checked all the references looking for old files, eventualy discovered I needed to do some bindingRedirects for Mvc, in my unit test project.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="0.0.0.0-5.1.0.0" newVersion="5.1.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>
国产ˉ祖宗 2024-12-22 17:36:41

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

如果您尝试对使用托管 C++ 创建的程序集中定义的接口进行存根,且该程序集具有特殊签名,则在创建存根时您将收到异常。

对于 Rhino Mocks 以及任何使用 System.Reflection.Emit 的模拟框架来说都是如此。

public interface class IFoo {
  void F(long bar);
};

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

该接口定义具有以下签名:

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

请注意,C++ 类型 long 映射到 System.Int32(或在 C# 中简称为 int)。导致问题的原因是有点晦涩的 modopt 如 Ayende Rahien 在 Rhino Mocks 邮件列表中所述

Another explanation for this type of problem involving managed C++.

If you try to stub an interface defined in an assembly created using managed C++ that has a special signature you will get the exception when the stub is created.

This is true for Rhino Mocks and probably any mocking framework that uses System.Reflection.Emit.

public interface class IFoo {
  void F(long bar);
};

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

The interface definition gets the following signature:

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

Note that the C++ type long maps to System.Int32 (or simply int in C#). It is the somewhat obscure modopt that is causing the problem as stated by Ayende Rahien on the Rhino Mocks mailing list .

电影里的梦 2024-12-22 17:36:41

我也遇到了这个错误,它是由引用 Any CPU 程序集的 Any CPU exe 引起的,而该程序集又引用了 x86 程序集。

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

I had this error too, it was caused by an Any CPU exe referencing Any CPU assemblies that in turn referenced an x86 assembly.

The exception complained about a method on a class in MyApp.Implementations (Any CPU), which derived MyApp.Interfaces (Any CPU), but in fuslogvw.exe I found a hidden 'attempt to load program with an incorrect format' exception from MyApp.CommonTypes (x86) which is used by both.

萌︼了一个春 2024-12-22 17:36:41

我不断地回到这个...
这里的许多答案都很好地解释了问题是什么,但没有解释如何解决它。

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

我不建议使用发布工具的删除功能,因为这往往会导致 IIS 崩溃。

I keep coming back to this...
Many of the answers here do a great job of explaining what the problem is but not how to fix it.

The solution to this is to manually delete the bin files in your projects published directory. It will clean up all the references and force the project to use the latest DLLs.

I don't suggest using the publish tools Delete function because this tends to throw off IIS.

小帐篷 2024-12-22 17:36:41

我通过“钻石”形项目依赖关系得到了这个:

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

我重新编译了项目 A,但没有重新编译项目 B,这允许项目 B“注入”旧版本的项目 D dll

I got this with a "diamond" shaped project dependency:

  • Project A uses Project B and Project D
  • Project B uses Project D

I recompiled project A but not Project B, which allowed Project B to "inject" the old version of the Project D dll

滥情哥ㄟ 2024-12-22 17:36:41

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

执行 Autofac 解析操作时,运行时将无法加载程序集之一。错误消息抱怨程序集“ImplementationAssembly”中类型“MyType”中的方法“MyMethod”没有实现。这些症状在 Windows Server 2012 R2 VM 上运行时出现,但在 Windows 10 或 Windows Server 2016 VM 上未出现。

ImplementationAssembly 引用了 System.Collections.Immutable 1.1.37,并包含 IMyInterface 接口的实现,该接口在单独的DefinitionAssemblyDefinitionAssembly 引用了 System.Collections.Immutable 1.1.36。

“未实现”的 IMyInterface 方法具有 IImmutableDictionary 类型的参数,该类型在 System.Collections 中定义.不可变

在程序目录中找到的 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>

I encountered this error in a context where I was using Autofac and a lot of dynamic assembly loading.

While performing an Autofac resolution operation, the runtime would fail to load one of the assemblies. The error message complained that Method 'MyMethod' in type 'MyType' from assembly 'ImplementationAssembly' does not have an implementation. The symptoms occurred when running on a Windows Server 2012 R2 VM, but did not occur on Windows 10 or Windows Server 2016 VMs.

ImplementationAssembly referenced System.Collections.Immutable 1.1.37, and contained implementations of a IMyInterface<T1,T2> interface, which was defined in a separate DefinitionAssembly. DefinitionAssembly referenced System.Collections.Immutable 1.1.36.

The methods from IMyInterface<T1,T2> which were "not implemented" had parameters of type IImmutableDictionary<TKey, TRow>, which is defined in System.Collections.Immutable.

The actual copy of System.Collections.Immutable found in the program directory was version 1.1.37. On my Windows Server 2012 R2 VM, the GAC contained a copy of System.Collections.Immutable 1.1.36. On Windows 10 and Windows Server 2016, the GAC contained a copy of System.Collections.Immutable 1.1.37. The loading error only occurred when the GAC contained the older version of the DLL.

So, the root cause of the assembly load failure was the mismatching references to System.Collections.Immutable. The interface definition and implementation had identical-looking method signatures, but actually depended on different versions of System.Collections.Immutable, which meant that the runtime did not consider the implementation class to match the interface definition.

Adding the following binding redirect to my application config file fixed the issue:

<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>
病毒体 2024-12-22 17:36:41

我们有同样的问题。事实证明,这是我们的控制台应用程序引用的库与我们的数据访问库引用的库之间的版本不匹配。

我意识到之前已经发布过类似的答案,但觉得添加图片应该确实有帮助。

当您引用类库时,您会将引用视为分层树。应用程序 A 引用库 B,而库 B 又引用库 C(见下图)。

比这更复杂(至少在 .net Framework 中)。您的应用程序不仅必须引用它使用的类库,还必须引用该类库的所有依赖项。应用程序 A 引用库 B 和库 C。库 B 引用库 C

实际情况

当库 B 引用库 C 的版本与应用程序 A 引用的库 C 的版本不同时,就会出现问题

这不work

如果你查看你的方法签名,你会发现一个来自库 C 的类型。它应该告诉你要检查哪个库的版本。

We had the same issue. It turned out to be a version mismatch between a library referenced by our console app and the library referenced by our data access library.

I realise answers similar to this have been posted before but feel the addition of pictures should really help.

When you reference a class library, you think of the references as a hierarchical tree. App A references Library B, which in turn references library C (see picture below).

How you imagine references

In reality however it's more tangled than that (at least in .net Framework). Your app must not only reference the class library it uses but also all the dependencies of that class library. App A references Library B and Library C. Library B references Library C

How it actually is

The problem arises when Library B references a different version of Library C to the version of Library C that App A references

This doesn't work

If you look at your method signature you'll find a type that's from library C. That should tell you which library to check the version of.

冷清清 2024-12-22 17:36:41

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

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

I had the same problem. I figured out that my assembly, which is loaded by the main program, had some references with "Copy Local" set to true. These local copies of references were looking for other references in the same folder, which did not exist because the "Copy Local" of other references was set to false. After the deletion of the "accidentally" copied references the error was gone because the main program was set to look for correct locations of references. Apparently the local copies of the references screwed up the sequence of calling because these local copies were used instead of the original ones present in the main program.

The take home message is that this error appears due to the missing link to load the required assembly.

风蛊 2024-12-22 17:36:41

由于选择了 x86 构建类型,我在 WCF 服务中得到了这个,导致 bin 位于 bin\x86 而不是 bin 下。选择 Any CPU 会导致重新编译的 DLL 到达正确的位置(我不会详细说明这是如何发生的)。

I got this in a WCF service due to having an x86 build type selected, causing the bins to live under bin\x86 instead of bin. Selecting Any CPU caused the recompiled DLLs to go to the correct locations (I wont go into detail as to how this happened in the first place).

海之角 2024-12-22 17:36:41

当接口引用第 3 方 dll (MWArray) 且“特定版本”设置为“True”时,我就遇到过这种情况,而实现的类引用了相同的 dll,但“特定版本”设置为“False”,所以类和接口有不同的版本引用同一个dll。

将两者设置为“特定版本”:“False”或“True”(取决于您的需要)修复了它。

It happened to me when an interface had a reference to 3rd party dll (MWArray) with 'Specific Version' set to 'True' while the implemented class had a reference to the same dll but with 'Specific Version' set to 'False', so class and interface had different versions reference to the same dll.

Setting both to 'Specific Version': 'False' or 'True' (depending on what you need) fixed it.

破晓 2024-12-22 17:36:41

当我尝试使用自定义 AssemblyLoadContext (无需创建 AppDomain)和共享类型(无需反射即可调用插件方法的接口)在 dot net 5 中实现插件程序集加载时,我遇到了这个问题。该线程没有任何帮助我。以下是我为解决此问题所做的操作:

  1. 为了允许调试插件加载而不会出现问题 - 将项目输出路径设置为主机应用程序 bin 文件夹。您将调试插件项目构建后获得的相同程序集。这可能是临时更改(仅用于调试)。
  2. 要修复 TypeLoadException,您需要将所有“合同程序集”引用的程序集作为共享程序集(运行时程序集除外)加载。检查加载器上下文实现(在构造函数中加载共享组件):

    public class PluginAssemblyLoadContext : AssemblyLoadContext
    {
        private AssemblyDependencyResolver _resolver;
        
        private IDictionary<string, Assembly> _loadedAssemblies;
        
        private IDictionary<string, Assembly> _sharedAssemblies;

        private AssemblyLoadContext DefaultAlc;

        private string _path;

        public PluginAssemblyLoadContext(string path, bool isCollectible, params Type[] sharedTypes)
             : this(path, isCollectible, sharedTypes.Select(t => t.Assembly).ToArray())
        {
        }

        public PluginAssemblyLoadContext(string path, bool isCollectible, params Assembly[] sharedAssemblies)
             : base(isCollectible: isCollectible)
        {

            _path = path;

            DefaultAlc = GetLoadContext(Assembly.GetExecutingAssembly()) ?? Default;

            var fileInfo = new FileInfo(_path);
            if (fileInfo.Exists)
            {
                _resolver = new AssemblyDependencyResolver(_path);

                _sharedAssemblies = new Dictionary<string, Assembly>(StringComparer.OrdinalIgnoreCase);
                foreach (var a in sharedAssemblies.Distinct())
                {
                    LoadReferencedAssemblies(a);
                }

                _loadedAssemblies = new Dictionary<string, Assembly>();

                var assembly = LoadFromAssemblyPath(fileInfo.FullName);

                _loadedAssemblies.Add(fileInfo.FullName, assembly);
            }
            else
            {
                throw new FileNotFoundException($"File does not exist: {_path}");
            }
        }

        public bool LoadReferencedAssemblies(Assembly assembly)
        {
            if (assembly == null)
            {
                throw new ArgumentNullException(nameof(assembly));
            }
            if (string.IsNullOrEmpty(assembly.Location))
            {
                throw new NotSupportedException($"Assembly location is empty string or null: {assembly.FullName}");
            }
            var alc = GetLoadContext(assembly);
            if (alc == this)
            {
                throw new InvalidOperationException($"Circular assembly loader dependency detected");
            }
            if (!_sharedAssemblies.ContainsKey(assembly.Location))
            {
                _sharedAssemblies.Add(assembly.Location, assembly);

                foreach (var an in assembly.GetReferencedAssemblies())
                {
                    var ra = alc.LoadFromAssemblyName(an);
                    LoadReferencedAssemblies(ra);
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        public IEnumerable<Type> GetCommandTypes<T>()
        {
            var cmdType = typeof(T);
            return _loadedAssemblies.Values.SelectMany(a => a.GetTypes()).Where(t => cmdType.IsAssignableFrom(t));
        }

        public IEnumerable<T> CreateCommands<T>(Assembly assembly)
        {
            foreach (var cmdType in GetCommandTypes<T>())
            {
                yield return (T)Activator.CreateInstance(cmdType);
            }
        }

        protected override Assembly Load(AssemblyName assemblyName)
        {
            var path = _resolver.ResolveAssemblyToPath(assemblyName);
            if (path != null)
            {
                if (_sharedAssemblies.ContainsKey(path))
                {
                    return _sharedAssemblies[path];
                }
                if (_loadedAssemblies.ContainsKey(path))
                {
                    return _loadedAssemblies[path];
                }
                return LoadFromAssemblyPath(path);
            }     
            return DefaultAlc.LoadFromAssemblyName(assemblyName);
        }
    }

用法:


var loader = new PluginAssemblyLoadContext(fullPath, false, typeof(IPluginCommand));
loader.CreateCommands<IPluginCommand>()...

I got this issue when I tried to implement plugin assembly loading in dot net 5 using custom AssemblyLoadContext (without AppDomain creation) and shared type (interface which you need to use to call plugin methods without reflection). Nothing from this thread helped me. Here is what I did to solve this issue:

  1. To allow debugging of plugin loading without a problems - setup project output path to host app bin folder. You will debug the same assembly you got after plugin project build. This is, probably, temporary change (just for debug).
  2. To fix TypeLoadException you need to load all 'contract assembly' referenced assemblies as shared assemblies (except runtime assemblies). Check loader context implementation (loading sharedAssemblies in constructor):

    public class PluginAssemblyLoadContext : AssemblyLoadContext
    {
        private AssemblyDependencyResolver _resolver;
        
        private IDictionary<string, Assembly> _loadedAssemblies;
        
        private IDictionary<string, Assembly> _sharedAssemblies;

        private AssemblyLoadContext DefaultAlc;

        private string _path;

        public PluginAssemblyLoadContext(string path, bool isCollectible, params Type[] sharedTypes)
             : this(path, isCollectible, sharedTypes.Select(t => t.Assembly).ToArray())
        {
        }

        public PluginAssemblyLoadContext(string path, bool isCollectible, params Assembly[] sharedAssemblies)
             : base(isCollectible: isCollectible)
        {

            _path = path;

            DefaultAlc = GetLoadContext(Assembly.GetExecutingAssembly()) ?? Default;

            var fileInfo = new FileInfo(_path);
            if (fileInfo.Exists)
            {
                _resolver = new AssemblyDependencyResolver(_path);

                _sharedAssemblies = new Dictionary<string, Assembly>(StringComparer.OrdinalIgnoreCase);
                foreach (var a in sharedAssemblies.Distinct())
                {
                    LoadReferencedAssemblies(a);
                }

                _loadedAssemblies = new Dictionary<string, Assembly>();

                var assembly = LoadFromAssemblyPath(fileInfo.FullName);

                _loadedAssemblies.Add(fileInfo.FullName, assembly);
            }
            else
            {
                throw new FileNotFoundException(
quot;File does not exist: {_path}");
            }
        }

        public bool LoadReferencedAssemblies(Assembly assembly)
        {
            if (assembly == null)
            {
                throw new ArgumentNullException(nameof(assembly));
            }
            if (string.IsNullOrEmpty(assembly.Location))
            {
                throw new NotSupportedException(
quot;Assembly location is empty string or null: {assembly.FullName}");
            }
            var alc = GetLoadContext(assembly);
            if (alc == this)
            {
                throw new InvalidOperationException(
quot;Circular assembly loader dependency detected");
            }
            if (!_sharedAssemblies.ContainsKey(assembly.Location))
            {
                _sharedAssemblies.Add(assembly.Location, assembly);

                foreach (var an in assembly.GetReferencedAssemblies())
                {
                    var ra = alc.LoadFromAssemblyName(an);
                    LoadReferencedAssemblies(ra);
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        public IEnumerable<Type> GetCommandTypes<T>()
        {
            var cmdType = typeof(T);
            return _loadedAssemblies.Values.SelectMany(a => a.GetTypes()).Where(t => cmdType.IsAssignableFrom(t));
        }

        public IEnumerable<T> CreateCommands<T>(Assembly assembly)
        {
            foreach (var cmdType in GetCommandTypes<T>())
            {
                yield return (T)Activator.CreateInstance(cmdType);
            }
        }

        protected override Assembly Load(AssemblyName assemblyName)
        {
            var path = _resolver.ResolveAssemblyToPath(assemblyName);
            if (path != null)
            {
                if (_sharedAssemblies.ContainsKey(path))
                {
                    return _sharedAssemblies[path];
                }
                if (_loadedAssemblies.ContainsKey(path))
                {
                    return _loadedAssemblies[path];
                }
                return LoadFromAssemblyPath(path);
            }     
            return DefaultAlc.LoadFromAssemblyName(assemblyName);
        }
    }

Usage:


var loader = new PluginAssemblyLoadContext(fullPath, false, typeof(IPluginCommand));
loader.CreateCommands<IPluginCommand>()...
半步萧音过轻尘 2024-12-22 17:36:41

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

I saw this in Visual Studio Pro 2008 when two projects built assemblies with the same name, one a class lib SDF.dll, and one that referenced the lib with assembly name sdf.exe.
When I changed the name of the referencing assembly, the exception went away

晨敛清荷 2024-12-22 17:36:41

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

This simply means that the implementation project is out of date in my cases. The DLL containing the interface was rebuilt but the implementation dll was stale.

缘字诀 2024-12-22 17:36:41

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

添加了 extern 方法,但我的粘贴有错误。 DllImportAttribute 被放在注释掉的行上。

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

确保该属性实际上包含在源代码中解决了该问题。

Here's my take on this error.

Added an extern method, but my paste was faulty. The DllImportAttribute got put on a commented out line.

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

Ensuring the attribute was actually included in source fixed the issue.

苍白女子 2024-12-22 17:36:41

我遇到了几乎同样的问题。我正在摸不着头脑是什么导致了这个错误。
我核对了一下,所有的方法都实现了。

在谷歌搜索上我得到了这个链接。根据 @Paul McLink 评论,这两个步骤解决了该问题。

  1. 重新启动 Visual Studio
  2. Clean、构建(重建)

错误消失

重新启动 VS 插件

谢谢 Paul :)

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

I faced almost same issue. I was scratching my head what is causing this error.
I cross checked, all the methods were implemented.

On Googling I got this link among other. Based on @Paul McLink comment, This two steps resolved the issue.

  1. Restart Visual Studio
  2. Clean, Build (Rebuild)

and the error gone.

Restart VS Plugin

Thanks Paul :)

Hope this helps someone who come across this error :)

初熏 2024-12-22 17:36:41

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

I also ran into this problem while running my unittests. The application ran fine and with no errors.
The cause of the problem in my case was that I had turned off the building of the test projects.
Reenabling the building of my testprojects solved the issues.

甜心小果奶 2024-12-22 17:36:41

就我而言,我之前在存储库外部的同级文件夹中引用了 mylib 项目 - 让我们称之为 v1.0

|-- 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 文件夹中的日期时间戳。任何过时的组件都是您的问题。

In my case I had previously referenced a mylib project in a sibling folder outside of the repo - let's call that v1.0.

|-- myrepo
|    |-- consoleApp
|    |-- submodules
|         |-- mylib (submoduled v2.0)
|-- mylib (stale v1.0)

Later I did it properly and used it via a git submodule - lets call that v2.0.
One project consoleApp however wasn't updated properly. It was still referencing the old v1.0 project outside of my git project.

Confusingly, even though the *.csproj was plainly wrong and pointing to v1.0, the Visual Studio IDE showed the path as the v2.0 project!
F12 to inspect the interface and class went to the v2.0 version too.

The assembly placed into the bin folder by the compiler was the v1.0 version, hence the headache.

That fact that the IDE was lying to me made it extra hard to realise the error.

Solution: Deleted project references from ConsoleApp and readded them.

General Tip: Recompile all assemblies from scratch (where possible, can't for nuget packages of course) and check datetime stamps in bin\debug folder. Any old dated assemblies are your problem.

情栀口红 2024-12-22 17:36:41

就我而言,它有助于重置 WinForms 工具箱。

在设计器中打开 Form 时出现异常;但是,可以编译并运行代码,并且代码的行为符合预期。异常发生在实现我引用的库之一的接口的本地 UserControl 中。更新该库后出现该错误。

UserControl 列在WinForms 工具箱中。可能 Visual Studio 保留了对该库的过时版本的引用,或者在某处缓存了过时的版本。

以下是我从这种情况中恢复的方法:

  1. 右键单击 WinForms 工具箱,然后单击上下文菜单中的重置工具箱(这将从工具箱中删除自定义项目)。
    就我而言,工具箱项目已恢复为默认状态;但是,工具箱中缺少指针箭头。
  2. 关闭 Visual Studio。
    在我的例子中,Visual Studio 因违规异常而终止并中止。
  3. 重新启动 Visual Studio。
    现在一切都进展顺利。

In my case it helped to reset the WinForms Toolbox.

I got the exception when opening a Form in the designer; however, compiling and running the code was possible and the code behaved as expected. The exception occurred in a local UserControl implementing an interface from one of my referenced libraries. The error emerged after this library was updated.

This UserControl was listed in the WinForms Toolbox. Probably Visual Studio kept a reference on an outdated version of the library or was caching an outdated version somewhere.

Here is how I recovered from this situation:

  1. Right click on the WinForms Toolbox and click on Reset Toolbox in the context menu. (This removes custom items from the Toolbox).
    In my case the Toolbox items were restored to their default state; however, the Pointer-arrow was missing in the Toolbox.
  2. Close Visual Studio.
    In my case Visual Studio terminated with a violation exception and aborted.
  3. Restart Visual Studio.
    Now everything is running smoothly.
冬天的雪花 2024-12-22 17:36:41

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

非常简短的答案

删除所有binobj目录并重建所有内容。 dll 的版本不匹配。

简短回答

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

在本例中,DummyItem 实现另一个程序集的接口。 SetShort 方法最近被添加到界面和 DummyItem 中 - 但包含 DummyItem 的程序集是参考界面程序集的先前版本而重建的。因此,SetShort 方法实际上在那里,但没有将其链接到接口中的等效方法的魔法。

长答案

如果您想尝试重现这一点,请尝试以下操作:

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

     公共接口 IInterface
     {
         字符串 GetString(字符串键);
         //短 GetShort(字符串键);
     }
    
  2. 创建第二个类库项目:实现(使用单独的解决方案),将 InterfaceDef.dll 复制到项目目录中并添加为文件引用,仅添加一个类,并构建:

     公共类 ImplementingClass : IInterface
     {
         #region IInterface 成员
         公共字符串 GetString(字符串键)
         {
             返回“你好世界”;
         }
    
         //公共短GetShort(字符串键)
         //{
         // 返回 1;
         //}
         #endregion
     }
    
  3. 创建第三个控制台项目:ClientCode,复制两个将dll文件放入项目目录下,添加文件引用,并在Main方法中添加如下代码:

     IInterface test = new ImplementingClass();
      string s = test.GetString("dummykey");
      Console.WriteLine(s);
      Console.ReadKey();
    
  4. 运行代码一次,控制台显示“hello world”

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

NOTE - If this answer doesn't help you, please take the time to scroll down through the other answers that people have added since.

Really short answer

Delete all your bin and obj directories and rebuild everything. The versions of the dlls don't match.

Short answer

This can happen if you add a method to an interface in one assembly, and then to an implementing class in another assembly, but you rebuild the implementing assembly without referencing the new version of the interface assembly.

In this case, DummyItem implements an interface from another assembly. The SetShort method was recently added to both the interface and the DummyItem - but the assembly containing DummyItem was rebuilt referencing the previous version of the interface assembly. So the SetShort method is effectively there, but without the magic sauce linking it to the equivalent method in the interface.

Long answer

If you want to try reproducing this, try the following:

  1. Create a class library project: InterfaceDef, add just one class, and build:

     public interface IInterface
     {
         string GetString(string key);
         //short GetShort(string key);
     }
    
  2. Create a second class library project: Implementation (with separate solution), copy InterfaceDef.dll into project directory and add as file reference, add just one class, and build:

     public class ImplementingClass : IInterface
     {
         #region IInterface Members
         public string GetString(string key)
         {
             return "hello world";
         }
    
         //public short GetShort(string key)
         //{
         //    return 1;
         //}
         #endregion
     }
    
  3. Create a third, console project: ClientCode, copy the two dlls into the project directory, add file references, and add the following code into the Main method:

      IInterface test = new ImplementingClass();
      string s = test.GetString("dummykey");
      Console.WriteLine(s);
      Console.ReadKey();
    
  4. Run the code once, the console says "hello world"

  5. Uncomment the code in the two dll projects and rebuild - copy the two dlls back into the ClientCode project, rebuild and try running again. TypeLoadException occurs when trying to instantiate the ImplementingClass.

最丧也最甜 2024-12-22 17:36:41

另一次,如果您的签名程序集版本不正确,则可能会出现此错误。这不是此原因的正常症状,但这是我遇到的情况

  • 一个 ASP.NET 项目包含程序集 A 和程序集 B,B 被强命名

  • 程序集 A 使用 Activator.CreateInstance 加载程序集 C(即没有对单独构建的 C 的引用)

  • C 是引用比当前版本更旧的程序集 B 构建的

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

The other time you can get this error is if you have an incorrect version of a signed assembly. It's not the normal symptom for this cause, but here was the scenario where I got it

  • an asp.net project contains assembly A and assembly B, B is strongly named

  • assembly A uses Activator.CreateInstance to load assembly C (i.e. there is no reference to C which is built separately)

  • C was built referencing an older version of assembly B than is currently present

hope that helps someone - it took me ages to figure this out.

尘曦 2024-12-22 17:36:41

我在以下场景中收到此错误。

  • 程序集 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。现在看来很明显了!

感谢原海报!

I received this error in the following scenario.

  • Both Assemblies A and B referenced System.Web.Mvc Version 3.0.0.0
  • Assembly A referenced Assembly B and had classes which implemented interfaces from Assembly B with methods which returned classes from System.Web.Mvc.
  • Assembly A upgraded to System.Web.Mvc Version 4.0.0.0
  • Assembly C ran the code below (FertPin.Classes.Contact was contained in Assembly A):

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

The fix for me was upgrading the System.Web.Mvc reference in Assembly B to 4.0.0.0. Seems obvious now!

Thanks to the original poster!

银河中√捞星星 2024-12-22 17:36:41

我遇到了同样的消息,以下是我们发现的内容:
我们在项目中使用第三方 dll。在这些新版本发布后,我们更改了项目以指向新的 dll 集并成功编译。

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

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

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

I came across the same message and here is what we have found:
We use third party dlls in our project. After a new release of those was out we changed our project to point to the new set of dlls and compiled successfully.

The exception was thrown when I tried to instatiate one of the their interfaced classes during run time.
We made sure that all the other references were up to date, but still no luck.
We needed a while to spot (using the Object Browser) that the return type of the method in the error message was a completely new type from a new, unreferenced assembly.

We added a reference to the assembly and the error disappeared.

  • The error message was quite misleading, but pointed more or less to the right direction (right method, wrong message).
  • The exception ocurred even though we did not use the method in question.
  • Which leads me to the question: If this exception is thrown in any case, why does the compiler not pick it up?
少女情怀诗 2024-12-22 17:36:41

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

I got this when my application didn't have a reference to another assembly defining a class that the method in the error message used. Running PEVerify gave more helpful error: "The system cannot find the file specified."

惟欲睡 2024-12-22 17:36:41

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

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

In addition to what the asker's own answer already stated, it may be worth noting the following. The reason this happens is because it is possible for a class to have a method with the same signature as an interface method without implementing that method. The following code illustrates that:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文