ilspy-decompile
Decompile a compiled assembly when you need the real implementation - a framework internal, a NuGet package you have no source for, or the exact behavior of a method before you upgrade across it. For source you already have, navigate with serena / the LSP instead; this is only for compiled .dll you cannot open otherwise.
Tool
ilspycmd, via either form (pick whichever the environment has):
dnx ilspycmd -h # needs the .NET 10 SDK
dotnet tool install --global ilspycmd # or pin per-repo in .config/dotnet-tools.json
Flags vary by version - confirm with ilspycmd -h.
Locate the assembly
- NuGet package:
~/.nuget/packages/<package-name>/<version>/lib/<tfm>/ - Build output:
./bin/Debug/net8.0/<AssemblyName>.dll(orRelease/.../publish/) - Runtime libraries: the shared-framework folder under the SDK (
dotnet --list-runtimesshows the paths). Reference assemblies hold no implementation - decompile the runtime.dll, not the ref.
Commands
ilspycmd MyLibrary.dll # whole assembly to stdout
ilspycmd -o ./decompiled MyLibrary.dll # to a folder
ilspycmd -p -o ./project MyLibrary.dll # reconstruct a .csproj
ilspycmd -t Namespace.ClassName MyLibrary.dll # one type only (fastest)
ilspycmd -il MyLibrary.dll # raw IL
Workflow: identify what you want to understand, locate the assembly, decompile the one type (-t) rather than the whole thing.
Modern-build caveats
ReadyToRun images, trimmed builds, and NativeAOT all reduce or omit decompilable code - prefer a non-trimmed Debug/Release build when you have the choice. Decompiling third-party code may be license-restricted; use it to understand, not to redistribute.