7

I'm experimenting with switch statement pattern matching, and I'm looking for a way to return false if either value in a two value tuple is zero. This is the code I'm trying:

static bool IsAnyValueZero((decimal, decimal) aTuple)
{
    switch(aTuple)
    {
        case (decimal, decimal) t when t.Item1 == 0 || t.Item2 == 0:
            return true;
    }
    return false;
}

In VSCode 1.47 and dotnetcore 3.14 I get a compile-time error:

CS8652: The feature 'type pattern' is in Preview`

What is the best compatible way to write this code?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
eodeluga
  • 608
  • 2
  • 7
  • 20
  • Do you have any setting overriding the `LangVersion` on your csproj? [Tuple pattherns](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#tuple-patterns) are a [C# 8.0](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8) feature. – Paulo Morgado Aug 25 '20 at 16:31
  • @PauloMorgado No – eodeluga Aug 25 '20 at 22:18
  • Does this answer your question? [How to use c# tuple value types in a switch statement](https://stackoverflow.com/questions/44355630/how-to-use-c-sharp-tuple-value-types-in-a-switch-statement) – Mike Nakis Mar 18 '22 at 20:41

1 Answers1

14

Type pattern in C# 8 does not support matching against tuple type in the form (decimal, decimal) t. But we can match against tuple type by specifying type ValueTuple that is used to represent tuples in C#:

public static bool IsAnyValueZero((decimal, decimal) aTuple)
{
    switch (aTuple)
    {
        case ValueTuple<decimal, decimal> t when t.Item1 == 0 || t.Item2 == 0:
            return true;
    }
    return false;
}

Here is demo.


Another way to write your code is to use tuple pattern:

public static bool IsAnyValueZero((decimal, decimal) aTuple)
{
    switch (aTuple)
    {
        case (decimal i1, decimal i2) when i1 == 0 || i2 == 0:
            return true;
    }
    return false;
}

Or we can rewrite this code the next way:

public static bool IsAnyValueZero((decimal, decimal) aTuple)
{
    switch (aTuple)
    {
        // Discards (underscores) are required in C# 8. In C# 9 we will
        // be able to write this case without discards.
        // See https://github.com/dotnet/csharplang/blob/master/proposals/csharp-9.0/patterns3.md#type-patterns.
        case (decimal _, decimal _) t when t.Item1 == 0 || t.Item2 == 0:
            return true;
    }
    return false;
}

Also we can specify matching values explicitly:

public static bool IsAnyValueZero((decimal, decimal) aTuple)
{
    switch (aTuple)
    {
        case (0, _):
            return true;
        case (_, 0):
            return true;
    }
    return false;
}

Here is demo.


C# 9 adds improvements to type pattern so that we will be able to match against tuple type using the next syntax (as in your original code sample):

switch (aTuple)
{
    // In C# 9 discards (underscores) are not required.
    case (decimal, decimal) t when t.Item1 == 0 || t.Item2 == 0:
        return true;
}

This feature is in C# 9 preview and it can be enabled.

Iliar Turdushev
  • 4,935
  • 1
  • 10
  • 23
  • 1
    Thank you. I'm confused though because I thought I was using a C# 7.0 feature by following this article. Where have a gone wrong? https://devblogs.microsoft.com/dotnet/do-more-with-patterns-in-c-8-0/#more-patterns-in-more-places – eodeluga Aug 25 '20 at 22:29