Proposal: Conditional Assignment Operator (=!
) for "assign only if different"
#9692
Replies: 6 comments 13 replies
-
It doesn't benefit from this. The pattern is used in property setter, not the caller.
This pattern is not commonly used used. The equality test code is usually in |
Beta Was this translation helpful? Give feedback.
-
I don't see hwo this patten is made better with |
Beta Was this translation helpful? Give feedback.
-
Instead of repeating the same logic in all property setters you can simply derive your observable objects from a base class so you only need to implement the comparison once. This way your properties become: // Option a.) - If you have a common storage in base
public MyType Property { get => Get<MyType>(); set => Set(value); }
// Option b.) - If you want to use allocate a field for each properties
public MyType Property { get => field; set => Set(ref field, value); } Where Option a.) can be useful if many properties may have their default value so they do not allocate memory in the base storage. You might want to choose Option b.) if you have boxing phobia (though every XAML-based frameworks with dependency objects work as option a.), and they perform pretty well).
Yes, myself included (see the docs/source for the example option a.) above). But as mentioned above, this way the logic is implemented once, which hardly justifies a brand new operator in the language. |
Beta Was this translation helpful? Give feedback.
-
This would be undesirable semantics. The setter would always fire. Even if the value didn't change. That breaks this pattern. |
Beta Was this translation helpful? Give feedback.
-
This would be a breaking change because =! Is already valid syntax for some types/scenarios, such as bool, due to C# not being a whitespace sensitive language public void M(ref bool x, bool y)
{
x =! y;
} |
Beta Was this translation helpful? Give feedback.
-
Hi, BTW: Value Equivalence like you proposed ist not necessarily symmetric. That has to be ensured by the developer. An asymmetric equivalence implementation would lead to unexpected assignment behavior I guess. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Proposal: Conditional Assignment Operator (=!)
Summary
Introduce a shorthand operator that assigns a value to a variable, field, property, or indexer only if the new value is not equal to the existing one.
obj.A.B.C.D =! newValue;
This expands to:
Motivation
A very common pattern in C# (especially in UI frameworks like WPF, WinForms, MAUI, Blazor, and MVVM code) is:
Problems with the current approach:
Repetition: the property or path (obj.A.B.C.D) must be written twice.
Error-prone: in long chains it’s easy to accidentally use a different member in the assignment.
Verbose: obscures the intent (“assign if different”) with boilerplate.
Events: extra/unnecessary setter invocations can trigger unwanted notifications.
A dedicated shorthand would reduce noise, clarify intent, and improve correctness.
Detailed Design
Syntax
left =! right;
Semantics
Equivalent to:
Uses EqualityComparer.Default for correct semantics across value and reference types.
The left-hand side is evaluated only once (see Desugaring below).
Works with locals, fields, properties, and indexers.
If left is a property returning a value type by copy (no ref return), rules are the same as ordinary assignment — =! cannot be applied.
Desugaring (compiler rewrite)
Example: property chain
obj.A.B.C.D =! newValue;
Becomes:
Example: indexer
items[i] =! value;
Becomes:
ref var __temp = ref items[i];
if (!EqualityComparer.Default.Equals(__temp, value))
__temp = value;
Notes
Ensures the left-hand side is evaluated once.
Avoids getter side effects being triggered twice.
Mirrors how compound assignments like += are lowered in Roslyn today.
Examples
Cleaner setters
Long property chains
// Before
// After
customer.Address.City =! city;
Indexers
items[i] =! newItem;
Alternatives
Continue using if (x != y) x = y; (status quo).
Use helper methods such as:
SetIfDifferent(() => obj.A.B.C.D, newValue);
(requires expressions, extra allocations/compilation).
Source generators to rewrite property setters.
Drawbacks
Introduces a new operator, increasing language complexity.
Potential learning curve (=! may not be obvious at first glance).
Requires compiler support to ensure single evaluation of left-hand side.
Prior Art
Kotlin’s takeIf / takeUnless (conditional value handling).
Many MVVM frameworks (e.g. Prism, MVVM Light) provide SetProperty(ref field, value) helpers for exactly this purpose.
Community has created numerous SetIfDifferent utilities.
Unresolved Questions
Should a custom comparer (IEqualityComparer) be supported, e.g. via an overload form?
Should the operator be overloadable for user-defined types?
Is =! the best syntax, or would alternatives (:=!, ?=, etc.) be more intuitive?
Conclusion
This proposal reduces boilerplate and errors in one of the most common C# patterns: assigning values only if they differ.
By providing a dedicated =! operator, C# can make intent explicit, improve maintainability, and align with patterns already ubiquitous in property-change scenarios.``
Beta Was this translation helpful? Give feedback.
All reactions