Entiende código .NET de terceros desconocido con Glass.NET
Dependes de una DLL de la que no tienes código fuente — un paquete abandonado, una biblioteca interna cuyo autor se fue, un SDK de proveedor con documentación escasa — y necesitas saber cómo funciona de verdad. Aquí tienes un flujo de investigación concreto en Glass.NET, el decompilador de .NET gratuito y de solo análisis estático que nunca ejecuta el ensamblado que inspecciona.
Tarde o temprano todo proyecto .NET acaba apoyándose en una DLL que nadie sabe explicar. El paquete se abandonó hace tres años y su repositorio ya no existe. La biblioteca de utilidades interna la escribió alguien que se fue de la empresa hace mucho. El SDK del proveedor viene con una documentación que se corta justo donde empieza tu pregunta. El comportamiento es incorrecto, o sorprendente, o simplemente no está documentado — y lo único que lo resolvería, el código fuente, es lo único que no tienes.
No lo necesitas. Un ensamblado .NET compilado lleva una descripción casi completa y recuperable de lo que hace: IL más metadatos ricos que nombran cada tipo, método y campo. Glass.NET lee eso y reconstruye C# legible, convirtiendo «no tengo ni idea de qué hace esta dependencia» en «déjame leer el método y averiguarlo». Es gratuito, y es estrictamente estático — lee los metadatos y el IL y reconstruye C#, y nunca ejecuta el ensamblado que inspecciona. Ese último punto es el que más importa aquí: puedes apuntar Glass a una dependencia en la que no confías, porque nada de la DLL se ejecuta jamás.
Pongámoslo concreto. Supón que dependes de un paquete NuGet abandonado — llamémoslo Acme.Resilience — que envuelve tus llamadas HTTP salientes en una política de reintentos. De forma intermitente, una llamada que debería haber fallado rápido se cuelga casi un minuto; otra que debería haber reintentado se rinde al instante. La documentación es un párrafo en un README muerto. Necesitas saber qué hace realmente RetryPolicy.ExecuteAsync: cómo calcula su backoff, qué excepciones trata como reintentables y si alguna vez habla con la red por su cuenta. Así se averigua.
Pon el ensamblado en disco y ábrelo
Primero, encuentra la DLL. Para una dependencia de NuGet está en la caché global de paquetes — %USERPROFILE%\.nuget\packages\<id>\<version>\lib\<tfm>\ en Windows, ~/.nuget/packages/... en el resto. Para una biblioteca interna o una entrega de proveedor, está donde tu compilación la copió, normalmente en bin/.
Ábrela en Glass.NET: arrastra el archivo a la ventana, o Archivo ▸ Abrir ensamblado. Glass carga los metadatos y lista el ensamblado en un árbol. No necesitas un PDB que coincida ni el código fuente original — basta con una .dll gestionada corriente, y Glass reconstruye el C# sin símbolos (hay más sobre eso en decompilar sin símbolos PDB). Y como abrir, leer y exportar son todas operaciones estáticas, este primer paso ya es seguro: un paquete que dudarías en ejecutar se puede abrir sin problema, porque Glass nunca lo ejecuta.
Oriéntate antes de leer
Resiste el impulso de lanzarte directo a un método. Dedica treinta segundos a captar primero la forma de la cosa. Despliega el ensamblado en su árbol de espacios de nombres ▸ tipos ▸ miembros — esto refleja la estructura que registró el compilador, así que ves de inmediato si tienes entre manos tres tipos ordenados o un amasijo de cien. Para Acme.Resilience esperarías una superficie pública pequeña — RetryPolicy, quizá un RetryOptions, un tipo de excepción o dos — por encima de un puñado de ayudantes internos.
La vista de información del ensamblado es la otra herramienta de orientación, y responde a una pregunta que quieres resolver pronto: ¿qué puede hacer siquiera esto? Muestra el framework objetivo, los atributos de producto y — la parte útil — los ensamblados referenciados. Si un «ayudante de reintentos» referencia System.Net.Http, es lo esperado; si referencia System.Diagnostics.Process o algo que no pinta nada en una biblioteca de backoff, has aprendido algo antes de leer una sola línea. El informe de exposición de Glass es un buen complemento aquí: pásalo para calibrar cuán legible es el ensamblado. Una biblioteca de estilo open source corriente debería leerse con claridad; si vuelve muy ofuscada, eso en sí es una señal que merece preguntarse. (Esa es la vista desde el otro lado del ofuscador hermano Nebula.NET, cuya virtualización de código es una función Pro — pero una dependencia corriente no tiene motivo para verse así.)
Decompila el punto de entrada
Ahora ve al código que de verdad llamas. La vía más rápida es Ir a todo (Ctrl+T), la apertura rápida difusa sobre cada tipo y miembro: escribe ExecuteAsync y salta directo a él, sin recorrer el árbol. Haz clic en el miembro y Glass lo decompila a C# bajo demanda.
Lee ExecuteAsync como el punto de entrada y léelo con foco — no intentas entender toda la biblioteca, solo el camino que toma tu llamada por ella. Verás el bucle de reintento, la llamada a lo que sea que calcula el retardo, el predicado que decide si una excepción es reintentable y dónde se invoca el trabajo real. Eso solo ya responde a menudo la pregunta. Pero la lógica interesante suele vivir un nivel más abajo, en los ayudantes a los que llama este método — así que síguelos.
Sigue las llamadas para entender el flujo de control
Aquí es donde un decompilador centrado en la navegación se gana su sitio, porque entender código desconocido consiste sobre todo en seguir llamadas, no en leer un método de arriba abajo.
- Ir a definición (F12, o Ctrl+Clic) sobre la llamada al ayudante del retardo te lleva directo a él. Ahora puedes leer exactamente cómo se calcula el backoff — y si ese cuelgue que viste es un retardo exponencial sin tope, de modo que un reintento tardío espera 60 segundos por diseño.
- Buscar todas las referencias (Shift+F12) sobre el campo
RetryOptions.MaxAttempts, volcándose al panel de resultados, muestra todos los sitios donde se lee el límite — así confirmas si el caso de «rendirse al instante» es un valor por defecto de1que se respeta al pie de la letra en algún lugar inesperado. - Jerarquía de llamadas y de tipos te dejan recorrer arriba y abajo la estructura — quién llama al método en el que estás, de qué deriva o qué implementa un tipo dado — mucho más rápido que adivinar por los nombres.
Las referencias se resuelven desde el propio árbol de sintaxis del decompilador, así que F12 aterriza en el símbolo correcto y no en una coincidencia de texto. El historial de navegación y una miga de pan de espacio de nombres ▸ tipo ▸ miembro te mantienen orientado mientras te mueves, para que puedas volver sobre tus pasos.
Baja al IL donde el C# sea ambiguo
Un método async como ExecuteAsync se reconstruye a partir de una máquina de estados generada por el compilador. El decompilador reconoce ese desazucarado y te devuelve C# limpio con async/await la mayoría de las veces — pero «la mayoría de las veces» es la trampa. Cuando el C# reconstruido se lee de forma rara, o no distingues exactamente dónde se captura una excepción frente a dónde queda el retardo esperado dentro de la máquina de estados, cambia el mismo miembro a la vista de IL. El IL es lo que de verdad se ejecuta, así que es la verdad de base; leerlo es el desempate cuando el C# es ambiguo. No hace falta vivir en el IL — recurre a él en el puñado de métodos donde la vista de alto nivel redondea un detalle que importa. (Leer el IL repasa qué estás mirando, y cómo decompilar una DLL de .NET a C# cubre el flujo de trabajo más amplio.)
Expórtalo a un proyecto para mirarlo en condiciones
Cuando quieras hacer algo más que leer — buscar con grep en todo el ensamblado cada HttpClient, Task.Delay o Process.Start, apuntarle un analizador, anotar lo que has deducido o conservar la biblioteca en disco como referencia permanente — expórtalo a un proyecto compilable. En la interfaz es Archivo ▸ Exportar a proyecto; desde un script es el subcomando glass export:
glass export Acme.Resilience.dll --output ./Acme.Resilience.Source
Eso escribe un .csproj más los archivos .cs reconstruidos y los recursos extraídos — un proyecto que tu cadena de herramientas entiende, no un volcado. Una biblioteca pequeña como esta suele recompilar sin más; una grande o inusual puede necesitar un breve repaso manual por referencias sin resolver o código generado por el compilador exótico. En cualquier caso, ya tienes el código fuente en disco para explorarlo en tu propio IDE, igual que si el autor lo hubiera entregado — y, de nuevo, la exportación nunca ejecutó el binario para producirlo. El análisis a fondo de eso está en convertir una DLL de vuelta en un proyecto compilable.
La idea
Una dependencia desconocida no es una caja negra. Ábrela, oriéntate con el árbol de tipos y la información del ensamblado, decompila el punto de entrada, sigue las llamadas para ver el flujo de control real, baja al IL donde el C# sea ambiguo y exporta a un proyecto cuando lo quieras en disco. En una tarde puedes saber con precisión qué hace Acme.Resilience con tus llamadas HTTP — el backoff sin tope, la rendición demasiado ansiosa, lo que resulte ser — en vez de adivinar por el comportamiento. Y como Glass.NET es gratuito y estrictamente estático, lo has hecho todo sin ejecutar una sola línea de código en la que no confiabas. Descarga Glass.NET, abre la DLL que te trae de cabeza y léela por ti mismo.
Prueba Nebula.NET
Endurece tu código .NET en minutos — empieza con la edición gratuita.