C# – Logical Evaluation with Pattern Matching

c

I'm working with another developer and we're trying to clean up and modernize some legacy code; all the while, trying to keep things readable and remain somewhat surgical with changes [1]. There's a method called GetResponse that returns a RestResponse object [2]:

private RestResponse GetResponse();

Sprinkled throughout a static helper class (we're moving towards OOP, so let's not focus on this point [3]), we have calls to this method that, get the object, determine if it's null, and, if it's not, does some processing:

RestResponse response = GetResponse();
if (response != null) {
    
}

With this in mind, the developer I'm working with, pointed out that the above snippet can be simplified to the following by using pattern matching:

if (GetResponse() is RestResponse response && response != null) {
    
}

However, my thought on the matter is simply, should it? For starters, I believe this is an abusive use of pattern matching since it is known that the return type of GetResponse is a RestResponse. Additionally, I believe it adds complexity to the logical evaluation, which forces other developers to slow down when reviewing or maintaining the code. All of that negativity and more, to save a single line of code? As such, I'm not exactly for the idea, but being that our environment is collaborative, I'm trying to keep an open mind. As such, I'd like to weigh in other opinions from the community before I solidify my opinion.

Personally, I believe the try pattern (e.g. if (TryGetResponse(out RestResponse response))) would be a better fit for the situation, but that's for another time.


Which is easier to read, understand and maintain; and, why?

Footnotes

1: By somewhat surgical, I mean that we're not trying to refactor chunks into new methods, objects, etc. Method bodies should still do the job they're intended to do, and everything they did before, they should still do. This is for the benefit of source control.

2: The only portions of the GetResponse method that are relevant to my question are the method name and the return type.

3: I have an additional task later to move things to an OOP approach and break it out of large monolithic methods; but, one step at a time.

Best Answer

To me, both variants look almost equally readable. Note the second one is almost identical in length compared to the first: it contains only one keyword more (is), the only real difference is the order in which the keywords are arranged. Note the response variable has also the same scope (!) in both variants.

Hence, this mostly boils down to be a matter of taste.

Of course, when additional conditions come in, breaking them down into a few separate steps is probably more readable, and for the first one this might be a little bit simpler: I would prefer

  RestResponse response = GetResponse();
  if (response != null && response.IsValid()) {

  }

over

  if (GetResponse() is RestResponse response && response != null && response.IsValid()) {

  }

but there are surely people who would suggest to break the second conditional into multiple lines like this

  if (GetResponse() is RestResponse response && 
      response != null && 
      response.IsValid()) {
  }

and say this is equally readable.

So I would leave such code currently in the form as it is written - regardless if it is in the first or second variant. Changing it always has a small risk of introducing typos, and when there is actually no benefit, why take that risk?

Related Topic