Table of Contents

Analyzers

DevBitsLab.Feeds includes Roslyn analyzers that help you follow best practices and catch common mistakes at compile time.

Installation

The analyzers are automatically included when you reference the DevBitsLab.Feeds NuGet package. No additional installation is required.

Version-Aware Behavior

The analyzers automatically adapt to your C# language version:

C# Version Behavior
C# 10-12 FEED001 always required; FEED002/FEED004 not shown
C# 13+ Full analyzer support including partial property suggestions

Note: On C# versions before 13, partial properties are not available, so the analyzers won't suggest using them.

Analyzer Summary

ID Severity Description C# Version
FEED001 ⚠️ Warning Missing InitializeBindableFeeds() call All
FEED002 ℹ️ Info Unnecessary InitializeBindableFeeds() call 13+
FEED003 ⚠️ Warning Feed property should be readonly All
FEED004 ℹ️ Info Consider using partial property 13+
FEED005 ⚠️ Warning Missing [BindableFeed] attribute All
FEED006 ℹ️ Info Debounce without UI context All
FEED007 ℹ️ Info Identity Select is unnecessary All
FEED008 ⚠️ Warning Filter predicate is constant All

FEED001

InitializeBindableFeeds() call required

Property Value
Severity ⚠️ Warning
Category Usage
C# Version All

When using [BindableFeed] on non-partial properties, you must call InitializeBindableFeeds() at the end of the constructor.

Note: On C# < 13, this is always required since partial properties aren't available.

Example

// ❌ Violation
public partial class MyViewModel : ObservableObject
{
    [BindableFeed]
    public Feed<Person> Person { get; }

    public MyViewModel()
    {
        Person = Feed<Person>.FromValue(new Person());
        // Missing InitializeBindableFeeds() call
    }
}

// ✅ Fixed
public MyViewModel()
{
    Person = Feed<Person>.FromValue(new Person());
    InitializeBindableFeeds();
}

FEED002

InitializeBindableFeeds() call is unnecessary

Property Value
Severity ℹ️ Info
Category Usage
C# Version 13+ only

When all [BindableFeed] properties are partial, the generator handles initialization automatically.

Note: This diagnostic only appears when using C# 13 or later.

Example

// ℹ️ Suggestion
public partial class MyViewModel : ObservableObject
{
    [BindableFeed]
    public partial Feed<Person> Person { get; set; }

    public MyViewModel()
    {
        Person = Feed<Person>.FromValue(new Person());
        InitializeBindableFeeds();  // Unnecessary
    }
}

FEED003

Feed property should be readonly

Property Value
Severity ⚠️ Warning
Category Design
C# Version All

Feed properties should not have public setters.

Example

// ❌ Violation
[BindableFeed]
public Feed<Person> Person { get; set; }

// ✅ Fixed options
public Feed<Person> Person { get; }
public Feed<Person> Person { get; private set; }
public Feed<Person> Person { get; init; }

FEED004

Consider using partial property

Property Value
Severity ℹ️ Info
Category Usage
C# Version 13+ only

Partial properties with [BindableFeed] are automatically initialized.

Note: This diagnostic only appears when using C# 13 or later.

Example

// ℹ️ Suggestion: Convert to partial
[BindableFeed]
public Feed<Person> Person { get; }

// ✅ Better: Partial property
[BindableFeed]
public partial Feed<Person> Person { get; set; }

FEED005

Missing [BindableFeed] attribute

Property Value
Severity ⚠️ Warning
Category Usage
C# Version All

Feed properties in ObservableObject should have [BindableFeed].

Example

// ❌ Violation
public partial class MyViewModel : ObservableObject
{
    public Feed<Person> Person { get; }
}

// ✅ Fixed
public partial class MyViewModel : ObservableObject
{
    [BindableFeed]
    public Feed<Person> Person { get; }
}

FEED006

Debounce may not marshal to UI thread

Property Value
Severity ℹ️ Info
Category Usage

When Debounce is called with useCallingContext: false, PropertyChanged events will fire on a background thread.

Example

// ℹ️ May cause UI binding issues
var debouncedFeed = sourceFeed.Debounce(
    TimeSpan.FromMilliseconds(300),
    useCallingContext: false);

// ✅ Default behavior marshals to UI thread
var debouncedFeed = sourceFeed.Debounce(TimeSpan.FromMilliseconds(300));

FEED007

Identity Select is unnecessary

Property Value
Severity ℹ️ Info
Category Performance

A Select operation that returns its input unchanged adds overhead without transforming the data.

Example

// ❌ Unnecessary
var feed = sourceFeed.Select(x => x);

// ✅ Just use the source directly
var feed = sourceFeed;

FEED008

Filter predicate is constant

Property Value
Severity ⚠️ Warning
Category Correctness

A Filter predicate that always returns true or false is usually a mistake.

Example

// ❌ Always true - no filtering
var feed = sourceFeed.Filter(_ => true);

// ❌ Always false - blocks all values
var feed = sourceFeed.Filter(_ => false);

// ✅ Use a meaningful predicate
var feed = sourceFeed.Filter(x => x.IsActive);

Suppressing Diagnostics

If you need to suppress a diagnostic:

Using Pragma

#pragma warning disable FEED003
public Feed<Person> Person { get; set; }
#pragma warning restore FEED003

Using SuppressMessage

[SuppressMessage("Design", "FEED003")]
public Feed<Person> Person { get; set; }

Using .editorconfig

[*.cs]
dotnet_diagnostic.FEED003.severity = none

See Also