c# - what - Assembly.GetTypes()-ReflectionTypeLoadException
system reflection c# (3)
Implementamos un marco de plugin para nuestra aplicación y cargamos ensambles de plugins usando Assembly.Loadfrom. Luego usamos GetTypes () y examinamos los tipos con cada archivo de complemento para las interfaces compatibles.
El usuario proporciona una ruta para los complementos y recorreremos cada uno de los archivos en la carpeta para ver si (el complemento) es compatible con nuestra interfaz de complementos. Si lo hace, creamos una instancia, si no, pasamos al siguiente archivo.
Construimos dos versiones de software a partir de una base de código (appA_1 y appA_2).
La carga de complementos funciona bien cuando la aplicación que se creó al mismo tiempo que el archivo del complemento carga los complementos. Sin embargo, si construimos appA_2 y apuntemos a la carpeta del complemento de la aplicación A_1, obtenemos una excepción cuando se llama a GetTypes ().
Una versión básica de nuestro código es;
var pluginAssembly = Assembly.LoadFrom(FileName);
foreach (var pluginType in pluginAssembly.GetTypes())
{
Obtenemos una excepción de "ReflectionTypeLoadException".
Esto es preocupante porque queremos que nuestra aplicación pueda cargar los tipos de cualquier complemento, creado por cualquier persona. ¿Hay algo que nos falta?
EDITAR: después de iterar a través de LoaderExceptions, hemos descubierto que hay un único archivo libPublic.dll que genera una excepción System.IO.FileNotFoundException. Lo extraño es que este archivo reside en el directorio de la aplicación y el complemento está referenciado al archivo del proyecto.
EDIT 2: en el registro de excepciones encontramos lo siguiente "Comparar el nombre del ensamblado resultó en la falta de coincidencia: Número de revisión"
Gracias a esta publicación pude resolver la ReflectionTypeLoadException
que UITypeEditor
en un UITypeEditor
. Es un ensamblado de diseñador (una etiqueta inteligente winforms utilizada en tiempo de diseño) de una biblioteca de clases personalizada, que escanea para algunos tipos.
/// <summary>
/// Get the types defined in the RootComponent.
/// </summary>
private List<Type> getAssemblyTypes(IServiceProvider provider)
{
var types = new List<Type>();
try
{
IDesignerHost host = (IDesignerHost)provider.GetService(typeof(IDesignerHost));
ITypeResolutionService resolution = (ITypeResolutionService)provider.GetService(typeof(ITypeResolutionService));
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
foreach (var assembly in ((AppDomain)sender).GetAssemblies())
{
if (assembly.FullName == args.Name)
{
return assembly;
}
}
return null;
};
Type rootComponentType = resolution.GetType(host.RootComponentClassName, false);
types = rootComponentType.Assembly.GetTypes().ToList();
}
catch
{
}
return types;
}
Obtendrá una versión de ensamblaje no coincidente. Como sus complementos se refieren a este libPublic.dll
, debe versionarlo con cuidado y, en particular, no superar su revisión / compilación / etc. números en cada compilación.
Unas pocas cosas:
Asegúrese de no tener ensamblados duplicados en el directorio del complemento (es decir, ensamblados que ya está cargando en la aplicación principal desde el directorio de la aplicación). De lo contrario, cuando cargue el complemento, puede cargar una copia adicional del mismo ensamblaje . Esto puede conducir a excepciones divertidas como:
El objeto (del tipo ''MyObject'') no es del tipo ''MyObject''.
Si obtiene la excepción al crear una instancia de un tipo, es posible que necesite manejar
AppDomain.AssemblyResolve
:private void App_Startup(object sender, StartupEventArgs e) { // Since we''ll be dynamically loading assemblies at runtime, // we need to add an appropriate resolution path // Otherwise weird things like failing to instantiate TypeConverters will happen AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; } private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { var domain = (AppDomain) sender; foreach (var assembly in domain.GetAssemblies()) { if (assembly.FullName == args.Name) { return assembly; } } return null; }
Me doy cuenta de que es un poco extraño tener que decirle al CLR que, para resolver un ensamblaje, busque el ensamblado con el nombre que estamos usando para resolverlo, pero he visto cosas extrañas sin él. Por ejemplo, podría instanciar tipos de un ensamblado de complemento, pero si intentara usar TypeDescriptor.GetConverter
, no encontraría el TypeConverter
para la clase, aunque podría ver el atributo Converter
en la clase.
En cuanto a sus ediciones, probablemente esto no sea lo que está causando su excepción actual, aunque puede encontrarse con estos problemas más adelante a medida que trabaja con sus complementos.