Browse pages
LS1013: Switch Leaves a Sealed Case to Its Discard Arm
LS1013 is a compiler check that reports a switch in Domain, the layer that holds business rules, over a state or closed-set record hierarchy that leaves a sealed case to its discard arm, because the C# compiler does not check the switch and the missed case reaches the discard arm at run time. This page states what the rule reports, where the error sits, and how to give every sealed case its own arm.
Reference#
What the Rule Enforces#
LS1013 enforces Model every Aggregate lifecycle with state records (litespec/backend/dotnet/domain#model-every-aggregate-lifecycle-with-state-records) and Model every closed set of domain values without enums (litespec/backend/dotnet/domain#model-every-closed-set-of-domain-values-without-enums). It runs in Domain only. Its category is LiteSpec.Domain. Severity and enablement follow the Analyzers overview.
What the Rule Reports#
The rule reports a switch expression or switch statement whose input type is an abstract record with sealed cases in the compilation, when the switch has a discard arm or a default label and no unguarded arm names a sealed case or an abstract intermediate that covers it. An arm with a when guard does not cover its case, because the guard can fail and pass the value to the discard arm. The rule reports one finding per switch, naming every sealed case left to the discard arm. The diagnostic sits on the discard pattern of a switch expression, or on the default label of a switch statement.
Failing Example#
public abstract record OrderState;
public sealed record OrderDraftState : OrderState;
public sealed record OrderPlacedState : OrderState;
public sealed record OrderCancelledState : OrderState;
public sealed class OrderRouter
{
public string Describe(OrderState state) => state switch
{
OrderDraftState draft => "draft",
OrderPlacedState placed => "placed",
_ => "other",
};
}Passing Example#
public abstract record OrderState;
public sealed record OrderDraftState : OrderState;
public sealed record OrderPlacedState : OrderState;
public sealed record OrderCancelledState : OrderState;
public sealed class OrderRouter
{
public string Describe(OrderState state) => state switch
{
OrderDraftState draft => "draft",
OrderPlacedState placed => "placed",
OrderCancelledState cancelled => "cancelled",
_ => "other",
};
}How to Fix#
Give every sealed case its own unguarded arm, and keep the discard arm or default label for a value outside the sealed set.
Notes#
What the Rule Ignores#
The rule does not report a switch with no discard arm or default label: the compiler warning CS8509 covers that switch. It does not report a switch over a type that is not an abstract record, a hierarchy with an unsealed case, or a hierarchy whose sealed cases sit outside the compilation. It does not run outside Domain.