Sundstrom.CheckedExceptions 1.9.8

There is a newer version of this package available.
See the version list below for details.
dotnet add package Sundstrom.CheckedExceptions --version 1.9.8
                    
NuGet\Install-Package Sundstrom.CheckedExceptions -Version 1.9.8
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Sundstrom.CheckedExceptions" Version="1.9.8">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Sundstrom.CheckedExceptions" Version="1.9.8" />
                    
Directory.Packages.props
<PackageReference Include="Sundstrom.CheckedExceptions">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Sundstrom.CheckedExceptions --version 1.9.8
                    
#r "nuget: Sundstrom.CheckedExceptions, 1.9.8"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Sundstrom.CheckedExceptions@1.9.8
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Sundstrom.CheckedExceptions&version=1.9.8
                    
Install as a Cake Addin
#tool nuget:?package=Sundstrom.CheckedExceptions&version=1.9.8
                    
Install as a Cake Tool

Checked Exceptions for C#

Take control of exception flow β€” enforce explicit handling or declaration in C#

Build NuGet License

❓ FAQ β€’ πŸ§ͺ Sample project β€’ πŸ“š Documentation β€’ πŸ“ Change Log


Demo

Click the image to watch the video om YouTube.

<a href="https://www.youtube.com/watch?v=ldJjMrqB8X4"><img src="screenshots/Screenshot3.png" alt="Video" width="500" /></a>

There are other videos in this playlist.


πŸš€ What It Does

CheckedExceptions is a Roslyn analyzer that makes exception handling explicit and reveals how exceptions propagate through your code.

If a method might throw an exception, the caller must either:

  • 🧯 Handle it (with try/catch), or
  • πŸ“£ Declare it (with [Throws(typeof(...))])

βœ… Inspired by Java’s checked exceptions<br /> βš™οΈ Fully opt-in<br /> πŸ’‘ Analyzer warnings by default β€” can be elevated to errors<br /> πŸ“„ Supports .NET and third-party libraries via XML documentation<br /> πŸ›  Includes code fixes to help you quickly handle or declare exceptions<br />


βœ… Quick Example

public class Sample
{
    public void Execute()
    {
        // ⚠️ THROW001: Unhandled exception type 'InvalidOperationException'
        Perform();
    }

    [Throws(typeof(InvalidOperationException))]
    public void Perform()
    {
        throw new InvalidOperationException("Oops!");
    }
}

βœ”οΈ Fix it by handling:

public void Execute()
{
    try { Perform(); }
    catch (InvalidOperationException) { /* handle */ }
}

Or by declaring:

[Throws(typeof(InvalidOperationException))]
public void Execute()
{
    Perform();
}

🧠 Why Use It?

  • Avoid silent exception propagation
  • Document intent with [Throws] instead of comments
  • Enforce better error design across your codebase
  • Works with unannotated .NET methods via XML docs
  • Plays nice with nullable annotations
  • Avoid confusing [Throws] with <exception> β€” enforce contracts, not just documentation

πŸ“¦ Installation

dotnet add package Sundstrom.CheckedExceptions

And define ThrowsAttribute in your project:

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Delegate | AttributeTargets.Property, AllowMultiple = true)]
public class ThrowsAttribute : Attribute
{
    public List<Type> ExceptionTypes { get; } = new();
    public ThrowsAttribute(Type exceptionType, params Type[] others) { … }
}

Find the full definition here.


βš™οΈ Configuration

.editorconfig

dotnet_diagnostic.THROW001.severity = warning
dotnet_diagnostic.THROW003.severity = warning

.csproj

<PropertyGroup>
  <WarningsAsErrors>nullable,THROW001</WarningsAsErrors>
</PropertyGroup>

JSON Settings

Add CheckedExceptions.settings.json:

{
  // Exceptions to completely ignore during analysis (Glob pattern).
  "ignoredExceptions": [
    "System.*",
    "System.ArgumentNullException",
    "!System.InvalidOperationException"
  ],

  // Exceptions to ignore but still report as informational diagnostics.
  "informationalExceptions": {
    "System.IO.IOException": "Propagation",
    "System.TimeoutException": "Always"
  },

  // If true, exceptions will not be read from XML documentation (default: false).
  "disableXmlDocInterop": false,

  // If true, control flow analysis, with redundancy checks, is disabled (default: false).
  "disableControlFlowAnalysis": false,

    // If true, basic redundancy checks are available when control flow analysis is disabled (default: false).
  "enableLegacyRedundancyChecks": false
}

Control flow analysis powers redundancy checks (e.g. unreachable code, redundant catches, unused exception declarations). Disabling it may improve analyzer performance slightly at the cost of precision.

Register in .csproj:

<ItemGroup>
  <AdditionalFiles Include="CheckedExceptions.settings.json" />
</ItemGroup>

πŸ” Diagnostics

ID Message
THROW001 ❗ Unhandled exception: must be caught or declared
THROW002 ℹ️ Ignored exception may cause runtime issues
THROW003 🚫 Avoid declaring exception type System.Exception
THROW004 🚫 Avoid throwing exception base type System.Exception
THROW005 πŸ” Duplicate declarations of the same exception type in [Throws]
THROW006 🧬 Incompatible Throws declaration (not declared on base member)
THROW007 🧬 Missing Throws declaration for base member's exception
THROW008 πŸ“¦ Exception already handled by declaration of super type in [Throws]
THROW009 🧹 Redundant catch typed clause
THROW010 ⚠️ [Throws] is not valid on full property declarations
THROW011 πŸ“„ Exception in XML docs is not declared with [Throws]
THROW012 🧹 Redundant exception declaration (declared but never thrown)
THROW013 🧹 Redundant catch-all clause (no remaining exceptions to catch)
THROW020 πŸ›‘ Unreachable code detected
IDE001 πŸ™ˆ Unreachable code (hidden diagnostic for editor greying)

πŸ›  Code Fixes

The analyzer offers the following automated code fixes:

  • βœ… Add exception declaration Adds [Throws(typeof(...))] attribute to declare the exception, or appends exception to existing attribute. (Fixes THROW001)

  • 🧯 Surround with try/catch Wraps the throwing site in a try/catch block. (Fixes THROW001)

  • βž• Add catch to existing try block Appends a new catch clause to an existing try. (Fixes THROW001)

  • 🧹 Remove redundant catch clause Removes a catch clause for an exception type that is never thrown. (Fixes THROW009)

  • πŸ”§ Add [Throws] declaration from base member Ensures overridden or implemented members declare the same exceptions as their base/interface. (Fixes THROW007)

  • πŸ”§ Add [Throws] declaration from XML doc Converts <exception> XML documentation into [Throws] attributes. (Fixes THROW011)


✨ Advanced Features

  • Lambdas, local functions, accessors, events – full support across member kinds
  • Exception inheritance analysis – understands base/derived exception relationships
  • XML documentation interop – merges [Throws] with <exception> tags from external libraries
  • Nullability awareness – respects #nullable enable context
  • Standard library knowledge – recognizes common framework exceptions (e.g. Console.WriteLine β†’ IOException)
  • Control flow analysis – detects whether exceptions are reachable, flags redundant catch clauses, and reports unreachable code caused by prior throws or returns

❓ Frequently Asked Questions (FAQ)

❓ How is this different from Java's checked exceptions?

Answer:

Java's checked exceptions are mandatory β€” the compiler enforces them, and every method must declare or handle them. While this promotes visibility, it also leads to friction, boilerplate, and workarounds like throws Exception.

This analyzer takes a modern, flexible approach:

  • ⚠️ Warnings by default, not errors β€” you’re in control.
  • ✍️ Opt-in declaration using [Throws] β€” only where it matters.
  • πŸ› οΈ Code fixes and suppression make adoption practical.
  • πŸ”„ Gradual adoption β€” use it for new code, leave legacy code untouched.
  • 🎯 Focused on intention, not obligation β€” you declare what callers need to know, not what int.Parse might throw.

βœ… Summary: This is exception design with intent, not enforcement by force. It improves exception hygiene without the rigidity of Java’s model.

❓ Can I use <exception> XML documentation tags instead of the [Throws] attribute?

Answer:

No β€” for your own code, <exception> tags are not treated as semantic declarations by the analyzer. While they are useful for documentation and IntelliSense, they are not part of the C# language’s type system and cannot be reliably analyzed or enforced.

Instead, we encourage and require the use of the [Throws] attribute for declaring exceptions in a way that is:

  • Explicit and machine-readable
  • Suitable for static analysis and enforcement
  • Integrated with code fixes and tooling support
🧩 Interoperability with external libraries

When analyzing external APIs (e.g., referenced .NET assemblies), we do recognize <exception> tags from their XML documentation β€” but only for interop purposes. That is:

  • We treat documented exceptions from public APIs as "declared" when [Throws] is not available.
  • This helps maintain compatibility without requiring upstream changes.

⚠️ Summary:
<exception> tags are respected for interop, but they are not a replacement for [Throws] in code you control.

❓ What about .NET Standard 2.0 support?

Answer:

The analyzer offers limited support for projects targeting .NET Standard 2.0. You’ll still get accurate diagnostics for your own code, as well as third-party libraries. However, members defined in the .NET Standard framework may not indicate which exceptions they throw.

This is due to a technical limitation: the XML documentation files for .NET Standard assemblies are often incomplete or malformed, making it impossible to extract reliable exception information.

βœ… Recommendation: Target a modern .NET SDK (e.g., .NET 6 or later) to get full analyzer support, including framework exception annotations.

❓ What about LINQ support?

Answer:

There’s no special support for LINQ at the moment. Since LINQ queries are typically deferred and represented as expression trees or objects, it’s difficult to determine where and when exceptions will actually be thrown.

We may explore better support in the future, but for now, these cases are considered out of scope.


🀝 Contributing

  1. Fork
  2. Create feature branch
  3. Push PR with tests & documentation
  4. ❀️

πŸ“œ License

MIT

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories (1)

Showing the top 1 popular GitHub repositories that depend on Sundstrom.CheckedExceptions:

Repository Stars
marinasundstrom/YourBrand
Prototype enterprise system for e-commerce and consulting services
Version Downloads Last Updated
2.5.1 659 9/5/2025
2.5.0 137 9/5/2025
2.2.4 421 9/1/2025
2.2.3 197 8/24/2025
2.2.2 167 8/24/2025
2.2.1 101 8/23/2025
2.2.0 96 8/23/2025
2.1.2 118 8/22/2025
2.1.1 176 8/14/2025
2.1.0 169 8/14/2025
2.0.3 170 8/12/2025
2.0.2 161 8/10/2025
2.0.1 157 8/9/2025
2.0.0 215 8/8/2025
1.9.9 245 8/6/2025
1.9.8 272 8/5/2025
1.9.7 248 8/5/2025
1.9.6 246 8/5/2025
1.9.5 239 8/5/2025
1.9.0 138 8/3/2025
1.8.5 51 8/2/2025
1.8.2 62 8/1/2025
1.8.1 128 7/31/2025
1.8.0 125 7/31/2025
1.7.1 116 7/30/2025
1.7.0 119 7/30/2025
1.6.7 123 7/29/2025
1.6.6 122 7/29/2025
1.6.5 136 7/28/2025
1.6.4 137 7/28/2025
1.6.3 146 7/28/2025
1.6.2 132 7/28/2025
1.6.1 153 7/27/2025
1.6.0 162 7/27/2025
1.5.2 251 7/26/2025
1.5.1 273 7/26/2025
1.5.0 270 7/26/2025
1.4.3 255 7/26/2025
1.4.2 399 7/25/2025
1.4.1 435 7/25/2025
1.4.0 482 7/24/2025
1.3.6 539 7/23/2025
1.3.5 551 7/23/2025
1.3.1 131 6/28/2025
1.3.0 122 6/28/2025
1.2.6 148 4/12/2025
1.2.5 142 4/12/2025
1.2.4 172 4/11/2025
1.2.3 218 11/30/2024
1.2.2 134 11/29/2024
1.2.1 145 11/28/2024
1.2.0 144 11/27/2024
1.1.9 144 11/26/2024
1.1.8 145 11/26/2024
1.1.7 140 11/26/2024
1.1.6 144 11/25/2024
1.1.5 145 11/25/2024
1.1.4 150 11/25/2024
1.1.3 156 11/24/2024
1.1.2 139 11/24/2024
1.1.1 140 11/24/2024
1.1.0 149 11/23/2024
1.0.9 150 11/22/2024
1.0.8 144 11/22/2024
1.0.7 144 11/21/2024
1.0.6 149 11/21/2024
1.0.5 147 11/20/2024
1.0.4 148 11/19/2024
1.0.3 144 11/19/2024
1.0.2 153 11/19/2024
1.0.1 157 11/19/2024
1.0.0 154 11/19/2024