Co-authored-by: omegaleo <5655201+omegaleo@users.noreply.github.com>
6.3 KiB
Fresh Start: Approaches to Override /// Comments with DocumentationAttribute
Goal
Make [Documentation] attribute the single source of truth that overrides any existing /// XML comments, working automatically for both library developers and NuGet package consumers.
Option 1: Roslyn Source Generator (RECOMMENDED) ⭐
How It Works
// Original code (what user writes):
namespace MyNamespace
{
[Documentation("MyClass", "A cool class")]
public class MyClass
{
[Documentation("DoWork", "Does the work")]
public void DoWork() { }
}
}
// Generated code (MyClass.Documentation.g.cs):
namespace MyNamespace
{
/// <summary>A cool class</summary>
public partial class MyClass
{
/// <summary>Does the work</summary>
public partial void DoWork();
}
}
Pros
✅ Standard .NET approach - Uses official Roslyn APIs ✅ Zero setup for consumers - Packaged as analyzer, auto-runs ✅ IDE friendly - Full IntelliSense support ✅ Non-invasive - Doesn't modify source files ✅ Incremental - Fast compilation with IIncrementalGenerator ✅ Easy debugging - Generated files visible in IDE ✅ NuGet ready - Package as analyzer, include in Documentation package
Cons
⚠️ Requires partial classes - Classes must be marked partial
⚠️ Learning curve - Source generators are complex
⚠️ Build-time only - Not visible until after build
Implementation
- Create
OmegaLeo.HelperLib.SourceGeneratorproject - Implement
IIncrementalGenerator - Find syntax nodes with
DocumentationAttribute - Generate partial classes with XML doc comments
- Package as analyzer with
<PackageReference Include="...SourceGenerator" OutputItemType="Analyzer"> - Include in Documentation package
Package Structure
OmegaLeo.HelperLib.SourceGenerator.nupkg
├── analyzers/dotnet/cs/
│ └── OmegaLeo.HelperLib.SourceGenerator.dll
└── build/
└── OmegaLeo.HelperLib.SourceGenerator.props
Option 2: Pre-Build File Rewriter
How It Works
// Before build:
[Documentation("MyMethod", "Does work")]
/// <summary>Old comment</summary> ← Will be replaced
public void MyMethod() { }
// After CommentGenerator runs (BEFORE compile):
[Documentation("MyMethod", "Does work")]
/// <summary>Does work</summary> ← New comment from attribute
public void MyMethod() { }
Pros
✅ Direct control - Actually modifies source files ✅ Works with existing code - No partial classes needed ✅ Visible immediately - Changes are in source ✅ Simple to understand - Just file modification
Cons
❌ Modifies source files - Can conflict with version control ❌ Timing issues - Must run before compile, after restore ❌ File locks - Can cause issues with IDEs ❌ Consumer complexity - Hard to package for NuGet users ❌ Merge conflicts - Generated changes in git
Option 3: Hybrid - Source Generator + XML Post-Processor
How It Works
- Source Generator: Generates partial classes with /// comments
- XmlDocGenerator: Post-processes XML files to add examples from attributes
// User writes:
[Documentation("DoWork", "Does work", null, "// example code")]
public void DoWork() { }
// Source Generator adds:
/// <summary>Does work</summary>
// XmlDocGenerator augments XML with:
<example><![CDATA[// example code]]></example>
Pros
✅ Best of both worlds - IDE sees comments, XML has examples ✅ Clean source - No manual /// needed ✅ Rich documentation - Full XML in packages
Cons
⚠️ Dual approach - Two tools to maintain ⚠️ Complexity - More moving parts
Option 4: Roslyn Analyzer + Code Fix
How It Works
- Analyzer detects
[Documentation]without matching/// - Shows warning/info diagnostic
- Code fix automatically adds
///from attribute - User can apply fix manually or in batch
Pros
✅ IDE integration - Shows as lightbulb/suggestion ✅ User control - User decides when to apply ✅ Standard pattern - How many .NET tools work
Cons
❌ Manual step - Not fully automatic ❌ User must trigger - Doesn't help consumers much
Recommendation: Option 1 (Source Generator)
Why?
- Industry standard - How modern .NET tools work
- Automatic for consumers - Zero setup
- IDE support - Full IntelliSense
- Non-invasive - No source file modification
- Maintainable - Clear separation of concerns
Migration Path
- Mark classes as
partial(one-time change) - Install source generator (packaged with Documentation)
- Build project
- IDE shows documentation immediately
For Consumers
# Install package
dotnet add package OmegaLeo.HelperLib.Documentation
# Write code
[Documentation("MyMethod", "Cool stuff")]
public partial class MyClass
{
public void MyMethod() { }
}
# Build - source generator runs automatically
dotnet build
# IDE shows: "Cool stuff" in IntelliSense!
What Needs to Change
Current State
- Classes/methods have
[Documentation]attribute - Some have manual
///comments (duplication) - XmlDocGenerator augments compiled XML
With Source Generator
- Classes/methods marked
partial - Only
[Documentation]attribute needed - Source generator creates
///at compile time - XmlDocGenerator still augments compiled XML with examples
File Changes Required
// Before:
public class BenchmarkUtility { }
// After:
public partial class BenchmarkUtility { } // Add 'partial'
Next Steps
- ✅ Get user confirmation on approach
- Create source generator project
- Implement IIncrementalGenerator
- Test locally
- Package as analyzer
- Test with consumer project
- Update all classes to partial
- Document the change
Questions for User
-
Are you okay with marking classes as
partial?- This is required for source generators
- Minimal code change
- Standard .NET pattern
-
Should we keep XmlDocGenerator for code examples?
- Source generator handles /// comments
- XmlDocGenerator can add tags to XML
- Complementary tools
-
Any concerns about source generators?
- Build-time dependency
- Requires rebuild to see changes
- Standard in .NET ecosystem