File: README.md
ILSpy [](https://nuget.org/packages/ICSharpCode.Decompiler) [](https://hachyderm.io/@ilspy) [](https://bsky.app/profile/ilspy.bsky.social) [](https://visualstudiogallery.msdn.microsoft.com/8ef1d688-f80c-4380-8004-2ec7f814e7de)
ILSpy is the open-source, cross-platform .NET assembly browser and decompiler. The desktop UI runs on Windows, Linux, and macOS (built on Avalonia).
Download: latest release | latest CI build (master) | Microsoft Store (RTM versions only)
Decompiler Frontends
Aside from the cross-platform desktop UI ILSpy (downloadable via Releases, see also plugins), the following other frontends are available:
- Visual Studio 2022/2026 ship with decompilation support for F12 enabled by default (using our engines v8.2 and v9.1 respectively).
- Our Visual Studio 2022 extension marketplace (works with VS 2026 as well)
- Our Visual Studio Code Extension repository | marketplace | open-vsx
- Our dotnet tool for Linux/Mac/Windows - check out ILSpyCmd in this repository | dotnet tool install
- C# for Visual Studio Code ships with decompilation support as well. To enable, activate the setting "Enable Decompilation Support".
- In Visual Studio 2019, you have to manually enable F12 support. Go to Tools / Options / Text Editor / C# / Advanced and check "Enable navigation to decompiled source"
- Our ICSharpCode.Decompiler and ILSpyX NuGet packages for your own projects
- Our Linux/Mac/Windows PowerShell cmdlets in this repository
Features
- Decompilation to C# (check out the language support status)
- Whole-project decompilation
- Open from NuGet feed, open from running process in addition to disk and GAC (Windows-only)
- Search for types/methods/properties (learn about the options)
- Hyperlink-based type/method/property navigation, bookmarks
- Base/Derived types navigation, history
- Assembly metadata explorer (feature walkthrough)
- BAML to XAML decompiler, !AvaloniaResources support
- ReadyToRun binary support for .NET Core (see the tutorial)
- Extensible via plugins
- Additional features in DEBUG builds (for the devs)
License
ILSpy is distributed under the MIT License. Please see the About doc for details,
as well as third party notices for included open-source libraries.
How to build
Windows:
- Make sure Windows PowerShell (at least version) 5.0 or PowerShell 7+ is installed.
- Clone the ILSpy repository using git.
- Execute
git submodule update --init --recursiveto download the ILSpy-Tests submodule (used by some test cases). - Install Visual Studio (documented version: 18.0/2026). You need the following workload components:
- Workload ".NET Desktop Development". This workload includes the .NET Framework 4.8 SDK and the .NET Framework 4.7.2 targeting pack, as well as the .NET 10.0 SDK (ILSpy.csproj targets .NET 10.0, but we have net472 projects too). Our unit tests require .NET 11.0 SDK.
- Workload "Visual Studio extension development" (Note: ILSpy.VSExtensions.slnx is separate from ILSpy.sln and thus this workload is optional)
- Individual Component "MSVC v143 - VS 2022 C++ x64/x86 build tools" (or similar)
- The VC++ toolset is optional; if present it is used for
editbin.exeto modify the stack size used by ILSpy.exe from 1MB to 16MB, because the decompiler makes heavy use of recursion, where small stack sizes lead to problems in very complex methods.
- The VC++ toolset is optional; if present it is used for
- Open ILSpy.sln in Visual Studio.
- NuGet package restore will automatically download further dependencies
- Run project "ILSpy" for the ILSpy UI
- Use the Visual Studio "Test Explorer" to see/run the tests
- If you are only interested in a specific subset of ILSpy, you can also use
- ILSpy.Desktop.slnf: for the cross-platform Avalonia UI and its tests
- ILSpy.XPlat.slnf: for the cross-platform CLI (ilspycmd) or PowerShell cmdlets
- ILSpy.VSExtensions.slnx: for the Visual Studio extensions
Note: Visual Studio includes a version of the .NET SDK that is managed by the Visual Studio installer - once you update, it may get upgraded too.
Please note that ILSpy is only compatible with the .NET 11.0 SDK and Visual Studio will refuse to load some projects in the solution (and unit tests will fail).
If this problem occurs, please manually install the .NET 11.0 SDK from here.
Unix / Mac:
- Make sure .NET 10.0 SDK (for run) and .NET 11.0 SDK (for tests) is installed.
- Make sure PowerShell is installed (formerly known as PowerShell Core)
- Clone the repository using git.
- Execute
git submodule update --init --recursiveto download the ILSpy-Tests submodule (used by some test cases). - Use
dotnet build ILSpy.Desktop.slnfto build the cross-platform Avalonia desktop UI; run it withdotnet run --project ILSpy. - Use
dotnet build ILSpy.XPlat.slnfto build only the CLI tool (ilspycmd) and PowerShell cmdlets.
How to contribute
- Report bugs
- If you want to contribute a pull request, please add https://github.com/icsharpcode/ILSpy/blob/master/BuildTools/pre-commit to your
.git/hooksto prevent checking in code with wrong formatting. We use tabs and not spaces. The build server runs the same script, so any pull requests using wrong formatting will fail.
Current and past contributors.
Privacy Policy for ILSpy
ILSpy does not collect any personally identifiable information, nor does it send user files to 3rd party services.
ILSpy does not use any APM (Application Performance Management) service to collect telemetry or metrics.
File: doc/ILAst Pattern Matching.md
ILAst Pattern Matching
Some IL instructions are classified as "patterns".
abstract class PatternMatchILInstruction : IStoreInstruction {
public ILInstruction TestedOperand { get; }
public ILVariable Variable { get; } // variable that receives the match result; may also be a temporary
}
public bool IsPattern(this ILInstruction inst, out ILInstruction testedOperand) => inst switch {
PatternMatchILInstruction pm => testedOperand = pm.TestedOperand; return true;
LogicNot logicNot => IsPattern(logicNot.Operand, out testedOperand),
Comp comp => testedOperand = comp.Left; return IsConstant(comp.Right);
}Every match.* instruction has the following properties:
- The
TestedOperandspecifies what gets matched against the pattern. - The
Variablestores the value ofTestedOperand(after converting to the matched type, if appropriate).- If this variable is also used outside the
match.*node, it corresponds to the C#single_variable_designation. - Otherwise it's a temporary used for pattern matching.
- I think in both cases it should have VariableKind.PatternVar
- If this variable is also used outside the
- The match instruction evaluates to
StackType.I4: 0 if the pattern was matched, 1 otherwise.
Some match instructions have a body with List nestedPatterns. Here every nested pattern must be a pattern according to IsPattern(), and the testedOperand of each must be a member of the Variable of the parent pattern. (members are: field, property, or deconstruction.result).
(exception: match.and/match.or, these instead require the testedOperand to be exactly the Variable of the parent pattern)
Examples
expr is var x
=>
match.var(x = expr)
=>textBlock (VarPattern) { stloc x(expr) // single eval expr final: ldc.i4 1 // match always }expr is T x
=>
match.type T(x = expr) {}
=>textBlock (TypePattern) { stloc x(isinst T(expr)) final: x != null }expr is C { A: var x } z
=>textmatch.type C(z = expr) { match.var(x = z.A) }=>
textBlock (TypePattern) { stloc z(isinst T(expr)) final: (z != null) && Block(VarPattern) { stloc x(z.A) final: ldc.i4 1 } }expr is C { A: var x, B: 42, C: { A: 4 } } z
=>textmatch.type C(z = expr) { match.var (x = z.A), comp (z.B == 42), match.recursive (temp2 = z.C) { comp (temp2.A == 4) } }=>
textBlock (TypePattern) { stloc z(isinst C(expr)) final: (z != null) && Block(VarPattern) { stloc x(z.A) final: ldc.i4 1 } && comp (z.B == 42) && Block(RecursivePattern) { stloc temp2(z.C) final: (temp2 != null) && comp (temp2.A == 4) } }expr is C(var x, var y, <4) { ... }
=>textmatch.recursive.type.deconstruct(C tmp1 = expr) { match.var(x = deconstruct.result0(tmp1)), match.var(y = deconstruct.result1(tmp1)), comp(deconstruct.result2(tmp1) < 4), }expr is C(1, D(2, 3))
=>textmatch.type.deconstruct(C c = expr) { comp(deconstruct.result0(c) == 1), match.type.deconstruct(D d = deconstruct.result1(c)) { comp(deconstruct.result0(d) == 2), comp(deconstruct.result1(d) == 2), } }x is >= 0 and var y and <= 100textmatch.and(tmp1 = x) { comp(tmp1 >= 0), match.var(y = tmp1), comp(tmp1 <= 100) }x is not C _
=>textlogic.not( match.type(C tmp1 = x) {} )expr is (var a, var b)(when expr is object)
=>textmatch.type.deconstruct(ITuple tmp = expr) { match.var(a = deconstruct.result0(tmp)), match.var(b = deconstruct.result1(tmp)), }expr is (var a, var b)(when expr is ValueTuple)
=>textmatch.recursive(tmp = expr) { match.var(a = tmp.Item1), match.var(b = tmp.Item2), }
File: doc/README.md
Files
License-Related
| File | Contents/Usage |
|---|---|
| ILSpyAboutPage.txt | Binary inclusion in ILSpy for About listing ILSpy components' licenses and third party notices link |
| third-party-notices.txt | Binary inclusion in ILSpy for third party libraries and code used in ILSpy and its components |
| copyright.txt | Copyright notice for ILSpy |
| license.txt | MIT license for ILSpy |
Other
| File | Contents |
|---|---|
File: ICSharpCode.Decompiler.PowerShell/README.md
ILSpy PowerShell Module
Built using https://github.com/PowerShell/PowerShell/blob/master/docs/cmdlet-example/command-line-simple-example.md as guideline
Sample usage: Demo.ps1
Tested with: PowerShell 5.1 on Windows, PowerShell 7+ on Windows and Mac
Missing
Publishing to https://www.powershellgallery.com/
- https://learn.microsoft.com/en-us/powershell/gallery/how-to/publishing-packages/publishing-a-package
- https://learn.microsoft.com/en-us/powershell/gallery/concepts/publishing-guidelines
Links for developing PS cmdlets
- https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/how-to-write-a-simple-cmdlet
- https://learn.microsoft.com/en-us/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands
- https://github.com/mmaitre314/PowerShellGet-Test-Binary-Module
- https://www.red-gate.com/simple-talk/dotnet/net-development/using-c-to-create-powershell-cmdlets-beyond-the-basics/
- https://www.google.com/search?q=write+a+module+for+powershell+core
File: ICSharpCode.ILSpyCmd/AsContainer/README.md
ILSpyCmd in Docker
Inspired by https://trustedsec.com/blog/hunting-deserialization-vulnerabilities-with-claude (and thus https://github.com/berdav/ilspycmd-docker)
Building the Image
There are two dockerfiles available - one for interactive use of ilspycmd (exploration), and the other for driving it from the outside (automation)
Interactive
docker build -t ilspycmd:91interactive . -f Dockerfile
docker run --rm -it -v ./:/docker ilspycmd:91interactive
Automation
docker build -t ilspycmd:91forautomation . -f DockerfileForAutomation
docker run --rm -v ./:/infolder -v ./out:/outfolder ilspycmd:91forautomation "/home/ilspy/.dotnet/tools/ilspycmd -p -o /outfolder /infolder/sample.dll"
File: ICSharpCode.ILSpyCmd/README.md
ilspycmd .NET Tool
To install:
dotnet tool install --global ilspycmdHelp output (ilspycmd --help):
/* Detailed source-code truncated for AI context efficiency. */Generate HTML diagrammers
Once you have an output folder in mind, you can adopt either of the following strategies
to generate a HTML diagrammer from a .Net assembly using the console app.
Manually before use
Create the output folder in your location of choice and inside it a new shell script.
Using the CMD shell in a Windows environment for example, you'd create a regenerate.cmd looking somewhat like this:
....\path\to\ilspycmd.exe ..\path\to\your\assembly.dll --generate-diagrammer --outputdir .
With this script in place, run it to (re-)generate the HTML diagrammer at your leisure. Note that --outputdir . directs the output to the current directory.
Automatically
If you want to deploy an up-to-date HTML diagrammer as part of your live documentation,
you'll want to automate its regeneration to keep it in sync with your code base.
For example, you might like to share the diagrammer on a web server or - in general - with users
who cannot or may not regenerate it; lacking either access to the ilspycmd console app or permission to use it.
In such cases, you can dangle the regeneration off the end of either your build or deployment pipeline.
Note that the macros used here apply to MSBuild for Visual Studio and your mileage may vary with VS for Mac or VS Code.
After building
To regenerate the HTML diagrammer from your output assembly after building,
add something like the following to your project file.
Note that the Condition here is optional and configures this step to only run after Release builds.
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
<Exec Command="$(SolutionDir)..\path\to\ilspycmd.exe $(TargetPath) --generate-diagrammer --outputdir $(ProjectDir)diagrammer" />
</Target>After publishing
If you'd rather regenerate the diagram after publishing instead of building, all you have to do is change the AfterTargets to Publish.
Note that the Target Name doesn't matter here and that the diagrammer is generated into a folder in the PublishDir instead of the ProjectDir.
<Target Name="GenerateHtmlDiagrammer" AfterTargets="Publish">
<Exec Command="$(SolutionDir)..\path\to\ilspycmd.exe $(TargetPath) --generate-diagrammer --outputdir $(PublishDir)diagrammer" />
</Target>Usage tips
Compiler-generated types and their nested types are excluded by default.
Consider sussing out big source assemblies using ILSpy first to get an idea about which subdomains to include in your diagrammers. Otherwise you may experience long build times and large file sizes for the diagrammer as well as a looong type selection opening it. At some point, mermaid may refuse to render all types in your selection because their definitions exceed the maximum input size. If that's where you find yourself, you may want to consider
- using
--generate-diagrammer-includeand--generate-diagrammer-excludeto limit the scope of the individual diagrammer to a certain subdomain - generating multiple diagrammers for different subdomains.
Advanced configuration examples
Above examples show how the most important options are used. Let's have a quick look at the remaining ones, which allow for customization in your project setup and diagrams.
Filter extracted types
Sometimes the source assembly contains way more types than are sensible to diagram. Types with metadata for validation or mapping for example. Or auto-generated types.
Especially if you want to tailor a diagrammer for a certain target audience and hide away most of the supporting type system to avoid noise and unnecessary questions.
In these scenarios you can supply Regular Expressions for types to --generate-diagrammer-include (white-list) and --generate-diagrammer-exclude (black-list).
A third option --generate-diagrammer-report-excluded will output a .txt containing the list of effectively excluded types next to the HTML diagrammer containing the effectively included types.
ilspycmd.exe --generate-diagrammer-include Your.Models..+ --generate-diagrammer-exclude .++Metadata|.+.Data..+Map --generate-diagrammer-report-excluded ..\path\to\your\assembly.dll --generate-diagrammer --outputdir .
This example
- includes all types in the top-level namespace
Your.Models - while excluding
- nested types called
Metadataand - types ending in
Mapin descendant.Data.namespaces.
- nested types called
Strip namespaces from XML comments
You can reduce the noise in the XML documentation comments on classes on your diagrams by supplying a space-separated list of namespaces to omit from the output like so:
ilspycmd.exe --generate-diagrammer-strip-namespaces System.Collections.Generic System ..\path\to\your\assembly.dll --generate-diagrammer --output-folder .
Note how System is replaced after other namespaces starting with System. to achieve complete removal.
Otherwise System.Collections.Generic wouldn't match the Collections.Generic left over after removing System., resulting in partial removal only.
Adjust for custom XML documentation file names
If - for whatever reason - you have customized your XML documentation file output name, you can specify a custom path to pick it up from.
ilspycmd.exe --generate-diagrammer-docs ..\path\to\your\docs.xml ..\path\to\your\assembly.dll --generate-diagrammer --output-folder .
File: ICSharpCode.ILSpyX/MermaidDiagrammer/ReadMe.md
How does it work?
To extract the type info from the source assembly, ILSpy side-loads it including all its dependencies.
The extracted type info is structured into a model optimized for the HTML diagrammer and serialized to JSON. The model is a mix between drop-in type definitions in mermaid class diagram syntax and destructured metadata about relations, inheritance and documentation comments.
The JSON type info is injected into the
template.htmlalongside other resources like thescript.jsat corresponding{{placeholders}}. It comes baked into the HTML diagrammer to enable
- accessing the data and
- importing the mermaid module from a CDN
locally without running a web server while also avoiding CORS restrictions.
In the final step, the HTML diagrammer app re-assembles the type info based on the in-app type selection and rendering options to generate mermaid class diagrams with the types, their relations and as much inheritance detail as you need.
File: ILSpy.AddIn.VS2022/README.md
Test cases for various types of projects as well as corresponding test plans are located in a separate repository.
https://github.com/icsharpcode/ILSpy-Addin-tests
File: ILSpy.Installer/README.md
Building the Installer
Dependencies
See https://github.com/oleg-shilo/wixsharp/wiki#dependencies
dotnet tool install --global wixGitHub runners installed software https://github.com/actions/runner-images/blob/main/images/windows/Windows2025-Readme.md at time
of writing WiX Toolset 3.14.1.8722
ILSpy Binaries
It is mandatory to first publish(.ps1) the respective target platforms, then setup can be built, eg
msbuild ILSpy.Installer.sln /p:Configuration="Release" /p:Platform="Any CPU"
msbuild ILSpy.Installer.sln /p:Configuration="Release" /p:Platform="Any CPU" /p:DefineConstants="ARM64"