ARTICLE AD BOX
C# 14 introduces extension members, including extension operators, which allow you to define operators generically instead of repeating them on every type.
Suppose I have an interface representing value-like domain objects:
public interface IValue<TSelf> where TSelf : struct, IValue<TSelf> { static abstract bool Equals(TSelf left, TSelf right); }Instead of implementing == and != on every struct that implements this interface, I centralize them using an extension block:
public static class ValueExtensions { extension<T>(T) where T : struct, IValue<T> { public static bool operator ==(T left, T right) => T.Equals(left, right); public static bool operator !=(T left, T right) => !T.Equals(left, right); } }Now any struct like this automatically gains equality operators:
public readonly struct Distance : IValue<Distance> { private readonly double meters; public Distance(double meters) { this.meters = meters; } public static bool Equals(Distance left, Distance right) => left.meters == right.meters; }This works correctly at compile time and runtime, but tools (for example, Rider and some Roslyn analyzers) still warn:
CA2231: Implement the equality operators and make their behavior identical to that of the Equals method
Because the operators live in an extension block rather than on the struct itself, the tool believes the type is “missing” required operators.
If extension operators are technically correct, is suppressing the tooling inspection the recommended approach? Or should types still provide thin forwarding operators like:
public static bool operator ==(Distance left, Distance right) => Equals(left, right);My question
Is it considered good practice to implement value-type equality operators generically through C# 14 extension blocks, or should value types still declare their own == and != operators to satisfy tooling and convention?
