KorsaR
KorsaR

Reputation: 572

What is generic pattern matching for in c# 7.1?

There is new feature introduced in C# 7.1 called generic pattern matching. One of the examples I found looks like this:

void Attack(IWeapon weapon, IEnemy enemy)
{
    switch (weapon)
    {
        case Sword sword:
            // process sword attack
            break;
        case Bow bow:
            // process bow attack
            break;
    }
}

But from my perspective it's a piece of incorrect design, which violates the second SOLID principle(open-close). I can't even think of the case where this might be needed, from my understanding if you came to situation when you need such switch, then you are doing something very wrong. From other hand, if this feature was added to language, there have to be a strong reason of doing so. So the question is - when would you need this assuming you're not creating poor architecture.

Upvotes: 2

Views: 671

Answers (3)

tmaj
tmaj

Reputation: 35037

A. A switch like this may be useful if you cannot (aka it's practically easier not to) modify classes you're working with, e.g. Exceptions.

B. pattern matching in switch can be much more sophisticated than just discriminating on types.

Pattern matching from What's new in C# 7.0 shows this versatility.

public static int SumPositiveNumbers(IEnumerable<object> sequence)
{
    int sum = 0;
    foreach (var i in sequence)
    {
        switch (i)
        {
            case 0:
                break;
            case IEnumerable<int> childSequence:
            {
                foreach(var item in childSequence)
                    sum += (item > 0) ? item : 0;
                break;
            }
            case int n when n > 0:
                sum += n;
                break;
            case null:
                throw new NullReferenceException("Null found in sequence");
            default:
                throw new InvalidOperationException("Unrecognized type");
        }
    }
    return sum;
}

Upvotes: 1

asaf92
asaf92

Reputation: 1855

I agree that having switch statements all over your codebase is harder to maintain and don't scale well.

However, if Sword and Bow are not dependent on the class that contains the Attack method, then you have no other option. And there are many examples for this like in serialization (as NibblyPig mentioned), but also when building a presentation layer, a ViewModel etc...

If Sword and Bow don't have the responsibility of processing an attack (which is where SRP is relevant) and you have a specific class for this case then you'll have to switch over different types. You don't want Sword to have a method that deals with serialization and a method that deals with what color will the Sword be in one specific menu etc...

Sure, it's helpful if you can avoid this by creating smart interfaces that abstract away the type and just allow you to access the information you need but sometimes you have no other options.

Also, sometimes language features can help to deal with legacy code and are not an indication of recommended good practices.

Upvotes: 0

NibblyPig
NibblyPig

Reputation: 52942

I agree that you can abuse it to violate open/closed, but you wouldn't use it in the way you have with your example (by taking in an interface).

Instead, consider a situation where you deserialize an object.

You might have a chat program and people can send messages, or images (pseudo code)

Object myObject = (object) _network.Read().Deserialize();

if (myObject is IImage) { }
else if (myObject is ITextMessage) { }

You could put this into a switch instead. It's still open closed because you can write additional types that extend IImage / ITextMessage.

You'd have to alter the fundamental functionality of the program to support things that aren't both of those. Or you could have an else { doSomeDefaultBehaviour(); }

Upvotes: 0

Related Questions