c# - La excepción TypeLoadException dice "sin implementación", pero está implementada
.net fusion (30)
Tengo un error muy raro en nuestra máquina de prueba. El error es:
System.TypeLoadException: Method ''SetShort'' in type ''DummyItem'' from assembly ''ActiveViewers (...)'' does not have an implementation.
Simplemente no puedo entender por qué. SetShort
está allí en la clase DummyItem
, e incluso he recompilado una versión con escrituras en el registro de eventos solo para asegurarse de que no sea un problema de implementación / control de versiones. Lo extraño es que el código de llamada ni siquiera llama al método SetShort
.
Acabo de actualizar una solución de MVC3 a MVC5 y comencé a recibir la misma excepción de mi proyecto de prueba de unidad.
Revisé todas las referencias en busca de archivos antiguos, finalmente descubrí que necesitaba hacer algunas Redireccionamientos de enlace para Mvc, en mi proyecto de prueba de unidad.
<?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>
Además de lo que ya se indicó en la respuesta del autor de la pregunta, puede valer la pena señalar lo siguiente. La razón por la que esto sucede es porque es posible que una clase tenga un método con la misma firma que un método de interfaz sin implementar ese método. El siguiente código ilustra eso:
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
Aquí está mi opinión sobre este error.
extern
un método extern
, pero mi pasta era defectuosa. El DllImportAttribute
se puso en una línea comentada.
/// <returns>(removed for brevity lol)</returns>[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWindowVisible(IntPtr hWnd);
Asegurar que el atributo se incluyera realmente en la fuente solucionó el problema.
Como anexo: esto también puede ocurrir si actualiza un paquete nuget que se utilizó para generar un ensamblaje falso. Supongamos que instala V1.0 de un paquete nuget y crea un ensamblaje falso "fakeLibrary.1.0.0.0.Fakes". A continuación, actualice a la versión más reciente del paquete nuget, digamos v1.1 que agregó un nuevo método a una interfaz. La biblioteca Fakes todavía está buscando la v1.0 de la biblioteca. Simplemente retire el ensamblaje falso y regenéelo. Si ese fue el problema, probablemente lo solucionará.
Conseguí esto con una dependencia de proyecto en forma de "diamante":
- Proyecto A usa Proyecto B y Proyecto D
- Proyecto B usa Proyecto D
Recopilé el proyecto A, pero no el proyecto B, lo que permitió que el Proyecto B "inyectara" la versión anterior de la dll del Proyecto D
Conseguí esto en un servicio WCF debido a que se seleccionó un tipo de construcción x86, lo que provocó que el bisn viviera en bin / x86 en lugar de bin. La selección de Cualquier CPU causó que las DLL recompiladas fueran a las ubicaciones correctas (no voy a entrar en detalles sobre cómo sucedió esto en primer lugar).
En mi caso, anteriormente había hecho referencia a un proyecto mylib
en una carpeta de hermanos fuera del repositorio. mylib
v1.0
.
|-- myrepo
| |-- consoleApp
| |-- submodules
| |-- mylib (submoduled v2.0)
|-- mylib (stale v1.0)
Más tarde, lo hice correctamente y lo usé a través de un submódulo de git: llamémoslo v2.0
. Sin embargo, una consoleApp
proyecto no se actualizó correctamente. Todavía hacía referencia al antiguo proyecto v1.0
fuera de mi proyecto git.
Confusamente , a pesar de que *.csproj
estaba claramente equivocado y apuntaba a v1.0
, ¡el IDE de Visual Studio mostró la ruta como el proyecto v2.0
! F12 para inspeccionar la interfaz y la clase fue a la versión v2.0
también.
El ensamblaje colocado en la carpeta bin por el compilador era la versión v1.0
, de ahí el dolor de cabeza.
El hecho de que el IDE me estaba mintiendo hizo que fuera muy difícil darse cuenta del error.
Solución : Se eliminaron las referencias de proyectos de ConsoleApp
y se leyeron.
Consejo general: Recompile todos los ensamblajes desde cero (cuando sea posible, no se puede buscar paquetes nuget, por supuesto) y verifique los sellos de fecha y hora en la carpeta bin/debug
. Cualquier asamblea anticuada es su problema.
En mi caso, ayudó a restablecer la caja de herramientas de WinForms.
Obtuve la excepción al abrir un Form
en el diseñador; sin embargo, compilar y ejecutar el código fue posible y el código se comportó como se esperaba. La excepción ocurrió en un UserControl
local implementando una interfaz desde una de mis bibliotecas referenciadas. El error surgió después de que esta biblioteca fue actualizada.
Este UserControl
fue listado en la caja de herramientas de WinForms. Probablemente Visual Studio mantuvo una referencia en una versión desactualizada de la biblioteca o estaba almacenando en caché una versión desactualizada en algún lugar.
Así es como me recuperé de esta situación:
- Haga clic derecho en WinForms Toolbox y haga clic en
Reset Toolbox
en el menú contextual. (Esto elimina elementos personalizados de la caja de herramientas).
En mi caso, los elementos de la caja de herramientas se restauraron a su estado predeterminado; sin embargo, la flecha del puntero faltaba en la caja de herramientas. - Cerrar Visual Studio.
En mi caso, Visual Studio terminó con una excepción de violación y se canceló. - Reinicie Visual Studio.
Ahora todo está funcionando sin problemas.
En mi caso, estaba intentando usar TypeBuilder
para crear un tipo. TypeBuilder.CreateType
lanzó esta excepción. Finalmente me di cuenta de que necesitaba agregar MethodAttributes.Virtual
a los atributos al llamar a TypeBuilder.DefineMethod
para un método que ayuda a implementar una interfaz. Esto se debe a que sin este indicador, el método no implementa la interfaz, sino un nuevo método con la misma firma (incluso sin especificar MethodAttributes.NewSlot
).
Encontré el mismo mensaje y esto es lo que hemos encontrado: usamos archivos DLL de terceros en nuestro proyecto. Después de que saliera una nueva versión, cambiamos nuestro proyecto para apuntar al nuevo conjunto de archivos DLL y compilamos con éxito.
La excepción fue lanzada cuando traté de demostrar una de sus clases conectadas durante el tiempo de ejecución. Nos aseguramos de que todas las demás referencias estuvieran actualizadas, pero aún así no hubo suerte. Necesitamos un tiempo para detectar (usando el Examinador de objetos) que el tipo de retorno del método en el mensaje de error era un tipo completamente nuevo de un ensamblaje nuevo, sin referencia.
Añadimos una referencia al montaje y el error desapareció.
- El mensaje de error era bastante engañoso, pero apuntaba más o menos a la dirección correcta (método correcto, mensaje incorrecto).
- La excepción ocurrió aunque no utilizamos el método en cuestión.
- Lo que me lleva a la pregunta: si, en cualquier caso, se lanza esta excepción, ¿por qué el compilador no la recoge?
Encontré este error en un contexto en el que estaba usando Autofac y una gran cantidad de carga dinámica de ensamblajes.
Al realizar una operación de resolución de Autofac, el tiempo de ejecución no podría cargar uno de los ensamblajes. El mensaje de error se quejó de que el Method ''MyMethod'' in type ''MyType'' from assembly ''ImplementationAssembly'' does not have an implementation
. Los síntomas ocurrieron cuando se ejecutaban en una máquina virtual Windows Server 2012 R2, pero no ocurrían en máquinas virtuales Windows 10 o Windows Server 2016.
InstallationAssembly hizo referencia a System.Collections.Immutable
1.1.37 y contenía implementaciones de una IMyInterface<T1,T2>
, que se definió en un DefinitionAssembly
separado. DefinitionAssembly
referenciado System.Collections.Immutable
1.1.36.
Los métodos de IMyInterface<T1,T2>
que fueron "no implementados" tenían parámetros de tipo IImmutableDictionary<TKey, TRow>
, que se definen en System.Collections.Immutable
.
La copia real de System.Collections.Immutable
encontrada en el directorio del programa fue la versión 1.1.37. En mi Windows Server 2012 R2 VM, el GAC contenía una copia de System.Collections.Immutable
1.1.36. En Windows 10 y Windows Server 2016, el GAC contenía una copia de System.Collections.Immutable
1.1.37. El error de carga solo ocurrió cuando el GAC contenía la versión anterior de la DLL.
Por lo tanto, la causa raíz de la falla en la carga del ensamblaje fueron las referencias no coincidentes a System.Collections.Immutable
. La definición y la implementación de la interfaz tenían firmas de métodos de aspecto idéntico, pero en realidad dependían de diferentes versiones de System.Collections.Immutable
, lo que significaba que el tiempo de ejecución no consideraba que la clase de implementación coincidiera con la definición de la interfaz.
Al agregar el siguiente enlace de redirección a mi archivo de configuración de la aplicación se solucionó el problema:
<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>
Encontré esto cuando cambié el nombre de un proyecto (y el nombre del ensamblaje), en el que dependía un proyecto ASP.NET. Los tipos en el proyecto web implementaron interfaces en el ensamblaje dependiente. A pesar de ejecutar la Solución limpia desde el menú Generar, el ensamblaje con el nombre anterior permaneció en la carpeta bin
, y cuando se ejecutó mi proyecto web
var types = AppDomain.CurrentDomain.
GetAssemblies().
ToList().
SelectMany( s => s.GetTypes() /* exception thrown in this call */ )
;
se lanzó la excepción anterior, quejándose de que los métodos de interfaz en los tipos de web de implementación no se implementaron realmente. La eliminación manual del ensamblaje en la carpeta bin
del proyecto web resolvió el problema.
Este error también puede ser causado si un ensamblaje se carga utilizando Assembly.LoadFrom (String) y hace referencia a un ensamblado que ya se cargó utilizando Assembly.Load (Byte []).
Por ejemplo, ha incrustado los ensamblados referenciados de la aplicación principal como recursos, pero su aplicación carga complementos de una carpeta específica.
En lugar de usar LoadFrom deberías usar Load. El siguiente código hará el trabajo:
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;
}
Esto simplemente significa que el proyecto de implementación está desactualizado en mis casos. La DLL que contiene la interfaz fue reconstruida pero la implementación dll fue obsoleta.
FWIW, obtuve esto cuando había un archivo de configuración que se redirigió a una versión inexistente de un ensamblaje al que se hace referencia. Fusión de registros para la victoria!
La otra vez que puede obtener este error es si tiene una versión incorrecta de un ensamblaje firmado. No es el síntoma normal de esta causa, pero aquí fue el escenario donde lo obtuve
un proyecto asp.net contiene el ensamblaje A y el ensamblaje B, B se nombra fuertemente
el ensamblaje A utiliza Activator.CreateInstance para cargar el ensamblaje C (es decir, no hay ninguna referencia a C, que se construye por separado)
C se construyó haciendo referencia a una versión anterior del conjunto B de la que está actualmente presente
Espero que esto ayude a alguien, me tomó años para resolver esto.
Me enfrenté a casi el mismo problema. Me estaba rascando la cabeza lo que está causando este error. Revisé, todos los métodos fueron implementados.
En Google tengo este enlace entre otros. Basado en el comentario de @Paul McLink, estos dos pasos resolvieron el problema.
- Reiniciar Visual Studio
- Limpiar, Construir (Reconstruir)
y el error se fue .
Gracias paul :)
Espero que esto ayude a alguien que encuentre este error :)
Obtuve esto cuando mi aplicación no tenía una referencia a otro conjunto que definía una clase que usaba el método en el mensaje de error. La ejecución de PEVerify dio un error más útil: "El sistema no puede encontrar el archivo especificado".
Otra explicación para este tipo de problema relacionado con C ++ administrado.
Si intenta apagar una interfaz definida en un ensamblaje creado con C ++ administrado que tiene una firma especial, obtendrá la excepción cuando se cree el apéndice.
Esto es cierto para Rhino Mocks y probablemente para cualquier marco de burla que use System.Reflection.Emit
.
public interface class IFoo {
void F(long bar);
};
public ref class Foo : public IFoo {
public:
virtual void F(long bar) { ... }
};
La definición de la interfaz obtiene la siguiente firma:
void F(System.Int32 modopt(IsLong) bar)
Tenga en cuenta que el tipo C ++ long
asigna a System.Int32
(o simplemente int
en C #). Es el modopt
un tanto oscuro que está causando el problema según lo declarado por Ayende Rahien en la lista de correo de Rhino Mocks .
Recibí este error después de una actualización reciente de Windows. Tenía una clase de servicio configurada para heredar de una interfaz. La interfaz contenía una firma que devolvía un ValueTuple, una característica bastante nueva en C #.
Todo lo que puedo adivinar es que la actualización de Windows instaló una nueva, pero incluso haciendo referencia explícita a ella, actualizando las redirecciones de enlaces, etc. El resultado final fue simplemente cambiando la firma del método a algo "estándar", supongo que podría decir.
Recibí este error en el siguiente escenario.
- Ambas asambleas A y B hicieron referencia a System.Web.Mvc versión 3.0.0.0
- El ensamblado A hizo referencia al ensamblaje B y tenía clases que implementaban interfaces desde el ensamblado B con métodos que devolvían clases desde System.Web.Mvc.
- Ensamblaje A actualizado a System.Web.Mvc versión 4.0.0.0
- La Asamblea C ejecutó el siguiente código (FertPin.Classes.Contact estaba contenido en la Asamblea A):
var target = Assembly.GetAssembly(typeof(FertPin.Classes.Contact));
La solución para mí fue actualizar la referencia System.Web.Mvc en la Asamblea B a 4.0.0.0. Parece obvio ahora!
Gracias al cartel original!
Recibí este error porque tenía una clase en un ensamblado ''C'' que estaba en la versión 4.5 del marco, implementando una interfaz en el ensamblaje ''A'' que estaba en la versión 4.5.1 del marco y sirviendo como la clase base para el ensamblaje ''B'' que también estaba en la versión 4.5.1 del framework. El sistema lanzó la excepción al intentar cargar el ensamblaje ''B''. Además, había instalado algunos paquetes nuget dirigidos a .net 4.5.1 en los tres ensamblajes. Por alguna razón, aunque las referencias de nuget no se mostraban en el ensamblaje ''B'', se estaba construyendo con éxito.
Resultó que el verdadero problema era que los ensamblajes hacían referencia a diferentes versiones de un paquete nuget que contenía la interfaz y la firma de la interfaz había cambiado entre las versiones.
Sigo volviendo a esto ... Muchas de las respuestas aquí explican cuál es el problema pero no cómo solucionarlo.
La solución a esto es eliminar manualmente los archivos bin en el directorio publicado de sus proyectos. Limpiará todas las referencias y forzará al proyecto a usar las últimas DLL.
No sugiero el uso de la función de eliminación de herramientas de publicación porque esto tiende a deshacerse de IIS.
También me encontré con este problema mientras ejecutaba mis pruebas de unidad. La aplicación funcionó bien y sin errores. La causa del problema en mi caso era que había desactivado la construcción de los proyectos de prueba. Rehabilitar la construcción de mis proyectos de prueba resolvió los problemas.
También recibí este error cuando anteriormente había habilitado la cobertura de código durante las pruebas de unidad para uno de los ensamblajes. Por alguna razón, Visual Studio "almacenó" la versión anterior de esta DLL en particular, aunque la había actualizado para implementar una nueva versión de la interfaz. Deshabilitando la cobertura de código se deshizo del error.
También tuve este error, fue causado por un archivo de cualquier CPU exe que hacía referencia a cualquier ensamblado de CPU que a su vez hacía referencia a un ensamblado x86.
La excepción se quejó de un método en una clase en MyApp.Implementations (cualquier CPU), que derivó de MyApp.Interfaces (cualquier CPU), pero en fuslogvw.exe encontré un intento oculto de "cargar un programa con un formato incorrecto" en MyApp .CommonTypes (x86) que utilizan ambos.
Tengo otra solución esotérica a este mensaje de error. Actualicé mi marco de trabajo de .Net 4.0 a 4.6, y mi proyecto de prueba de unidad me estaba dando el error "System.TypeLoadException ... no tiene una implementación" cuando intenté crear. También dio un segundo mensaje de error sobre el mismo método supuestamente no implementado que decía "La tarea ''BuildShadowTask'' falló inesperadamente". Ninguno de los consejos aquí pareció ayudar, así que busqué "BuildShadowTask" y encontré una publicación en MSDN que me llevó a usar un editor de texto para eliminar estas líneas del archivo csproj del proyecto de prueba de unidad.
<ItemGroup>
<Shadow Include="Test References/MyProject.accessor" />
</ItemGroup>
Después de eso, ambos errores desaparecieron y el proyecto se construyó.
Vi esto en Visual Studio Pro 2008 cuando dos proyectos crearon ensamblajes con el mismo nombre, uno una clase lib SDF.dll y uno que hacía referencia a la biblioteca con el nombre del ensamblado sdf.exe. Cuando cambié el nombre del conjunto de referencia, la excepción desapareció
Yo tuve el mismo problema. Me di cuenta de que mi ensamblaje, que está cargado por el programa principal, tenía algunas referencias con "Copiar Local" establecido en verdadero. Estas copias locales de referencias buscaban otras referencias en la misma carpeta, que no existían porque la "Copia local" de otras referencias estaba configurada en falso. Después de la eliminación de las referencias copiadas "accidentalmente", el error desapareció porque el programa principal se configuró para buscar las ubicaciones correctas de las referencias. Aparentemente, las copias locales de las referencias arruinaron la secuencia de la llamada porque se usaron estas copias locales en lugar de las originales presentes en el programa principal.
El mensaje principal es que este error aparece debido a que falta el enlace para cargar el ensamblaje requerido.
NOTA : Si esta respuesta no le ayuda, tómese el tiempo para desplazarse hacia abajo a través de las otras respuestas que la gente ha agregado desde entonces.
Respuesta corta
Esto puede suceder si agrega un método a una interfaz en un conjunto y luego a una clase de implementación en otro conjunto, pero reconstruye el conjunto de implementación sin hacer referencia a la nueva versión del conjunto de interfaz.
En este caso, DummyItem implementa una interfaz desde otro conjunto. El método SetShort se agregó recientemente a la interfaz y al DummyItem, pero el ensamblaje que contiene DummyItem se reconstruyó haciendo referencia a la versión anterior del ensamblaje de la interfaz. Entonces, el método SetShort está efectivamente allí, pero sin la salsa mágica que lo vincula con el método equivalente en la interfaz.
Respuesta larga
Si quieres intentar reproducir esto, prueba lo siguiente:
Cree un proyecto de biblioteca de clases: InterfaceDef, agregue solo una clase y cree:
public interface IInterface { string GetString(string key); //short GetShort(string key); }
Cree un proyecto de biblioteca de segunda clase: Implementación (con solución separada), copie InterfaceDef.dll en el directorio del proyecto y agregue como referencia de archivo, agregue solo una clase y genere:
public class ImplementingClass : IInterface { #region IInterface Members public string GetString(string key) { return "hello world"; } //public short GetShort(string key) //{ // return 1; //} #endregion }
Cree un tercer proyecto de consola: ClientCode, copie las dos dlls en el directorio del proyecto, agregue referencias de archivos y agregue el siguiente código en el método Main:
IInterface test = new ImplementingClass(); string s = test.GetString("dummykey"); Console.WriteLine(s); Console.ReadKey();
Ejecuta el código una vez, la consola dice "hola mundo".
Descomente el código en los dos proyectos dll y reconstrúyalo: copie los dos dlls nuevamente en el proyecto ClientCode, reconstruya e intente ejecutar nuevamente. La excepción TypeLoadException ocurre cuando se intenta crear una instancia de ImplementingClass.