我们的测试机器上有个很奇怪的bug。错误是:

系统。来自程序集“activeviewer(…)”的类型“DummyItem”中的方法“SetShort”没有实现。

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


当前回答

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

添加了一个extern方法,但我的粘贴是错误的。DllImportAttribute被放到一个注释出来的行。

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

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

其他回答

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

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

对于Rhino mock和任何使用System.Reflection.Emit的mock框架都是如此。

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)。正如Ayende Rahien在Rhino Mocks邮件列表中所述,这是一个有点晦涩的modopt导致的问题。

当我尝试在dot net 5中使用自定义的AssemblyLoadContext(没有AppDomain创建)和共享类型(你需要使用它来调用插件方法而没有反射)实现插件程序集加载时,我得到了这个问题。这篇文章对我没有任何帮助。以下是我解决这个问题的方法:

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


    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>()...

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

当在设计器中打开窗体时,我得到了异常;然而,编译和运行代码是可能的,并且代码的行为符合预期。异常发生在实现我引用的库之一的接口的本地UserControl中。更新此库后出现错误。

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

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

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

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

简短的回答

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

在本例中,DummyItem实现了来自另一个程序集的接口。SetShort方法最近被添加到接口和DummyItem中—但是包含DummyItem的程序集是引用先前版本的接口程序集重新构建的。因此SetShort方法有效地存在,但没有将其链接到接口中的等效方法。

长回答

如果你想尝试复制这个,试试下面的方法:

Create a class library project: InterfaceDef, add just one class, and build: public interface IInterface { string GetString(string key); //short GetShort(string key); } 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 } 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(); Run the code once, the console says "hello world" 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.

另一种情况是,有符号程序集的版本不正确。这不是这种疾病的正常症状,但这是我患病的情况

asp.net项目包含程序集A和程序集B, B是强命名的 程序集A使用Activator。CreateInstance加载程序集C(即没有对单独构建的C的引用) C是引用程序集B的较旧版本构建的

希望这能帮助到一些人,我花了很长时间才弄明白。