1

Is there an easier way to do this logical? It is used often and each time I have the impression that it is unnecessary.

if (x != y)
x = y;

In more time-consuming methods, you have to use variables so as not to recalculate them every time.

I think there has to be a better way than, for example:

var MyF = CheckSomething();
if (X != MyF)
 X = MyF;

I have a class name Person. It has a property Information.

If you change the value of this field, the system performs calculations which, based on the value set, changes the contents of other fields in the system.

The problem is that I don't want to change the contents of this field when it is identical to the value I have to compare.

Because it will slow down the program significantly.

And I wonder if there is an easier way than writing the above condition each time for each field that I want to check.

I can't change this class, all I can do is set the property value.

The problem is that there are hundreds of these classes with dozens of properties

(Thematic) Similar problem and solution :

string SomeValue = SetValue();
string NewValue;
if (SomeValue == null)
    NewValue = "NULL RECEIVED";
else
    NewValue = SomeValue;

Is the same as

string SomeValue = SetValue();
string NewValue = SomeValue ?? "NULL RECEIVED";

And this shortcut is what I'm looking for.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
Walczak Jakub
  • 92
  • 1
  • 10
  • 8
    Why can't you simply do `X = CheckSomething()`? What is the point of that "if", if the result always is X == MyF? In other words, from what you've shown us, the previous value of X is irrelevant. Unless there's some weird overwriting (custom properties? custom `!=` operator? with side effects?) hidden here. – freakish Feb 28 '22 at 09:10
  • 1
    I second @freakish comment. Either show the real code with the real issue or just rewrite as they pointed out since the end result will be identical. Is it that `X` is a property that you want to avoid making a write-call to? Or is `X` a variable like `MyF`, in which case it doesn't matter that you simply write directly to it? Please explain the *problem* you're trying to solve with that code. – Lasse V. Karlsen Feb 28 '22 at 09:12
  • Because changing this field for more complex classes causes recalculation. If I set this value every time, the program will have to recalculate the whole thing just to set the same value. This will cause a significant drop in performance. – Walczak Jakub Feb 28 '22 at 09:14
  • 4
    `Because changing this field for more complex classes causes recalculation` So you are using a property that has a slow setter? That's bad. Make it a method. That won't make it faster, but it will alert the programmer to the fact that calling it could be time-consuming. – Matthew Watson Feb 28 '22 at 09:16
  • 3
    @WalczakJakub changing a *field* cannot cause any recalculation. Did you mean that X is a *property*? And there's a custom logic in that property? Look at how bad that design is: we cannot possibly know that simply from looking at the code. And so the code you've written indeed looks weird. Perhaps you should refactor it and simply write a method `UpdateX()` which inside will check if recalculation is needed. If you can't modify the code of the class, then I guess you can always add an extension. – freakish Feb 28 '22 at 09:19
  • Also it's trivial to write a `SetX(X newX)` method which checks the value: `if (_currentX != newX) { /* Update _currentX */ }` – Matthew Watson Feb 28 '22 at 09:21
  • I've updated the problem. @MatthewWatson The problem is that there are hundreds of these classes with dozens of properties. In theory, I could use dynamic in a method to refer to the fields I need every time, but that's why I'm asking, is there any simpler way to do it? – Walczak Jakub Feb 28 '22 at 09:26
  • If you cannot change the class so simply create an extension method for update the property or even on class – sa-es-ir Feb 28 '22 at 09:28
  • 1
    @WalczakJakub So your choice is to write the check for EVERY place where you set the property, or once for each property in its implementation. It should be obvious which is the correct approach. Just bite the bullet and fix it, IMO. – Matthew Watson Feb 28 '22 at 09:42
  • 2
    ^^ What Matthew says, but be prepared to encounter code that expects this "bug" to happen (performing calculations while value has not really been changed). – Fildor Feb 28 '22 at 09:49
  • I understand, but with the library we have to work at, it's a job for many, many weeks. Going back to the heart of the question: I understand that there is no shortened version of the code not to do it in the above-mentioned way? I added another example, maybe there is something similar that I can use in my case? – Walczak Jakub Feb 28 '22 at 13:37
  • I think that your second code example, the one starting with `var MyF = CheckSomething();`, does not convey the critical information that you are trying to mutate the property of an object. It's not immediately obvious that `X` is a property. I would suggest to edit this example like this `var value = CheckSomething(); if (myObject.X != value) myObject.X = value;`, with `value` being a probably more meaningful name for the variable `MyF`. – Theodor Zoulias Feb 28 '22 at 14:08

1 Answers1

0

My suggestion is to use self containing blocks, in order to reduce the scope of the value-carrying variables to their associated if statements:

{ var v = GetInformation(); if (person.Information != v) person.Information = v; }
{ var v = GetAddress(); if (person.Address != v) person.Address = v; }
{ var v = GetPhone(); if (person.Phone != v) person.Phone = v; }

Another idea could be to use a generic EnsureValue method:

EnsureValue(person, x => x.Information, (x, v) => x.Information = v, GetInformation());
EnsureValue(person, x => x.Address, (x, v) => x.Address = v, GetAddress());
EnsureValue(person, x => x.Phone, (x, v) => x.Phone = v, GetPhone());

Here is the implementation of the EnsureValue:

public static void EnsureValue<TSource, TProperty>(TSource source,
    Func<TSource, TProperty> getter,
    Action<TSource, TProperty> setter,
    TProperty value,
    IEqualityComparer<TProperty> comparer = default)
{
    comparer ??= EqualityComparer<TProperty>.Default;
    if (comparer.Equals(getter(source), value)) return;
    setter(source, value);
}

I don't think that it makes your code more readable though.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104