Bring Java-style checked exceptions to C#: enforce handling or declaration.
CheckedExceptions is a Roslyn analyzer that makes exception handling explicit.
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.
⚙️ Fully opt-in.
💡 Analyzer warnings by default, errors if you choose.
public class Sample
{
public void Execute()
{
// ⚠️ THROW001: Unhandled exception
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();
}- 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
dotnet add package Sundstrom.CheckedExceptionsAnd define ThrowsAttribute in your project:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Delegate, AllowMultiple = true)]
public class ThrowsAttribute : Attribute
{
public List<Type> ExceptionTypes { get; } = new();
public ThrowsAttribute(Type exceptionType, params Type[] others) { … }
}Find the full definition here.
dotnet_diagnostic.THROW001.severity = warning
dotnet_diagnostic.THROW003.severity = warning<PropertyGroup>
<WarningsAsErrors>nullable,THROW001</WarningsAsErrors>
</PropertyGroup>Add CheckedExceptions.settings.json:
{
"ignoredExceptions": [ "System.ArgumentNullException" ],
"informationalExceptions": {
"System.IO.IOException": "Propagation",
"System.TimeoutException": "Always"
}
}Register in .csproj:
<ItemGroup>
<AdditionalFiles Include="CheckedExceptions.settings.json" />
</ItemGroup>| ID | Description |
|---|---|
THROW001 |
Unhandled exception: must be caught or declared |
THROW003 |
Avoid general Exception in [Throws] |
THROW004 |
Avoid throwing Exception directly |
THROW005 |
Duplicate [Throws] declarations |
THROW006 |
Declared on override, missing from base |
THROW007 |
Declared on base, missing from override |
- ✅ Add missing
[Throws] - 🧯 Add try/catch block
- 🪛 Suppress with
#pragmaor[SuppressMessage]
- Supports lambdas, local functions, accessors, events
- Analyzes exception inheritance trees
- Merges
[Throws]with<exception>from XML docs - Handles nullability context (
#nullable enable) - Understands standard library exceptions (e.g.
Console.WriteLine→IOException)
- Fork
- Create feature branch
- Push PR with tests & documentation
- ❤️