スイッチで遊ぶ



イントロ
Cの経度7とCの角8では、“スイッチ”いくつかの新しい機能を得た.
今回は、「スイッチ」を使います.

環境
  • .ネット5.0.100

  • C≧7(一定パターン)以前

    プログラム.cs
    class Program
    {
        static void Main(string[] args)
        {
            int id = 1;
            switch(id)
            {
                case 0:
                    Console.WriteLine("Id was 0");
                    break;
                case 1:
                    Console.WriteLine("Id was 1");
                    break;
                default:
                    Console.WriteLine("Not found");
                    break;
            }
        }
    }
    
    定数値のみを使用できます.

    新しいパターン

    型パターン
    C≧7の後、タイプを使用できます.
    型のパターンで、ターゲットオブジェクトを変換できるかどうかを確認した後、変換されたインスタンスが作成されます.

    レコードサンプル.cs
        public record RecordSample(int Id, string Name);
    

    プログラム.cs
        static void Main(string[] args)
        {
            RecordSample r = new (3, "Hello"); 
            Play((object)r);
        }
        private static void Play(object target)
        {
            switch(target)
            {
                case RecordSample r:
                    Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
                    break;
                default:
                    Console.WriteLine("Not found");
                    break;
            }
        }
    

    結果
    Record Id: 3 Name: Hello
    

    タプルパターン

    プログラム.cs
            static void Main(string[] args)
            {
                (int Id, string Name) t = (0, "Hello");
                Play((object)t);
            }
            private static void Play(object target)
            {
                switch(target)
                {
                    case RecordSample r:
                        Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
                        break;
                    case (0, "Hello"):
                        Console.WriteLine("Tuple");
                        break;
                    default:
                        Console.WriteLine("Not found");
                        break;
                }
            }
    

    結果
    Tuple
    

    プロパティパターン

    プログラム.cs
            static void Main(string[] args)
            {
                var r = new RecordSample(1, "Hello");
                Play((object)r);
            }
            private static void Play(object target)
            {
                switch(target)
                {
                    case RecordSample { Id: 1} r:
                        Console.WriteLine($"Property pattern Id: {r.Id} Name: {r.Name}");
                        break;
                    case RecordSample r:
                        Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
                        break;
                    default:
                        Console.WriteLine("Not found");
                        break;
                }
            }
    

    結果
    Property pattern Id: 1 Name: Hello
    
    私もいくつかのより多くのパターンを使用できます.


    新しいパターン(ex . typeパターン)では、より特定の条件に分けることができます.

    プログラム.cs
            static void Main(string[] args)
            {
                var r = new RecordSample(1, "Hello");
                Play((object)r);
            }
            private static void Play(object target)
            {
                switch(target)
                {
                    case RecordSample r when r.Id < 0:
                        Console.WriteLine($"Record1 Id: {r.Id} Name: {r.Name}");
                        break;
                    case RecordSample r when r.Id >= 1:
                        Console.WriteLine($"Record2 Id: {r.Id} Name: {r.Name}");
                        break;
                    case RecordSample r:
                        Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
                        break;
                    default:
                        Console.WriteLine("Not found");
                        break;
                }
            }
    

    結果
    Record2 Id: 1 Name: Hello
    

    スイッチ式
    Cでは、“スイッチ式”を追加しました.
    私は以下のようにリファクタリングすることができます.

    以前

    プログラム.cs
            static void Main(string[] args)
            {
                int id = 1;
                string message = GetMessage(id);
                Console.WriteLine(message);
            }
            private static string GetMessage(int id)
            {
                switch(id)
                {
                    case 0:
                        return "ID was 0";
                    case 1:
                        return "ID was 1";
                    default:
                        return "Other";
                }
            }
    

    結果
    ID was 1
    

    アフター

    プログラム.cs
            static void Main(string[] args)
            {
                int id = 1;
                string message = id switch
                {
                    0 => "ID was 0",
                    1 => "ID was 1",
                    _ => "Other"
                };
                Console.WriteLine(message);
            }
    

    結果
    ID was 1
    
    switch文と同じパターンを使用できます.

    資源
  • Pattern Matching - C# Guide | Microsoft Docs
  • C# 8.0 - Pattern Matching in C# 8.0 | Microsoft Docs
  • C# switch statement | Microsoft Docs
  • switch expression - C# reference | Microsoft Docs
  • Do more with patterns in C# 8.0 | .NET Blog
  • Programming C# 8.0

  • C# 8.0 パターン マッチング | ++C++; // 未確認飛行 C ブログ

  • どのように多くのインスタンスが作成されますか?

    質問
    たとえば、このコードを実行すると、いくつのインスタンスが生成されますか?

    プログラム.cs
            static void Main(string[] args)
            {
                var r = new RecordSample(0, "Hello");
                Play((object)r);
            }
            private static void Play(object target)
            {
                switch(target)
                {
                    case RecordSample r when r.Id < 0:
                        Console.WriteLine($"Record1 Id: {r.Id} Name: {r.Name}");
                        break;
                    case RecordSample r when r.Id >= 1:
                        Console.WriteLine($"Record2 Id: {r.Id} Name: {r.Name}");
                        break;
                    case RecordSample r:
                        // Execute here
                        Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
                        break;
                    default:
                        Console.WriteLine("Not found");
                        break;
                }
            }
    

    アンサー
    つのインスタンスだけが作成されます.

    分解杭
    私はilspyによってこのコードを分解しますhttps://marketplace.visualstudio.com/items?itemName=icsharpcode.ilspy-vscode ).
    private static void Play(object target)
    {
        RecordSample recordSample = target as RecordSample;
        if ((object)recordSample != null)
        {
            if (recordSample.Id < 0)
            {
                Console.WriteLine($"Record1 Id: {recordSample.Id} Name: {recordSample.Name}");
                return;
            }
            RecordSample recordSample2 = recordSample;
            if (recordSample2.Id >= 1)
            {
                Console.WriteLine($"Record2 Id: {recordSample2.Id} Name: {recordSample2.Name}");
                return;
            }
            RecordSample recordSample3 = recordSample;
            Console.WriteLine($"Record Id: {recordSample3.Id} Name: {recordSample3.Name}");
        }
        else
        {
            Console.WriteLine("Not found");
        }
    }
    
  • インスタンスは"as record sample "として作成されます
  • それがNULLでないならば、if文の条件の下で操作を実行するためにif文を使用してください.
  • つのインスタンスだけが作成されます.

    のようなオブジェクトを変換する
    タイプスクリプトでは、インスタンスがRecordSampleクラスと同じプロパティを持つ場合に変換できます.

    レコードのサンプル.TS
    export class RecordSample {
        public id: number = -1;
        public name: string = "";
    }
    

    プログラム.TS
    import { RecordSample } from "./record-sample";
    
    export function main(){
        const s = {
            id: 1,
            name: "Hello"
        };
        const r: RecordSample = s; // <- OK
    }
    
    私もこのようにC .
    まず、変換するメソッドを追加します.

    レコードサンプル.cs
        public record RecordSample
        {
            public int Id { get; init; }
            public string Name { get; init; } = "";
            public RecordSample(int id, string name)
            {
                Id = id;
                Name = name;
            }
            public static bool TryParse(object original, out RecordSample? result)
            {
                result = null;
                var type = original.GetType();
                var idValue = type.GetProperty("Id")?.GetValue(original)?.ToString();
                var nameValue = type.GetProperty("Name")?.GetValue(original)?.ToString();
                if(idValue == null || nameValue == null)
                {
                    return false;
                }
                if(int.TryParse(idValue.ToString(), out var id) == false)
                {
                    return false;
                }
                result = new RecordSample(id, nameValue);
                return true;
            }
        }
    
  • Object.GetType Method (System) | Microsoft Docs
  • Type.GetProperty Method (System) | Microsoft Docs
  • そして、これをswitch文に追加します.
            private static void Play(object target)
            {
                switch(target)
                {
                    case RecordSample r:
                        Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
                        break;
                    case var o when RecordSample.TryParse(o, out var r):
                        Console.WriteLine($"Property Id: {r!.Id} Name: {r!.Name}");
                        break;
                    default:
                        Console.WriteLine("Not found");
                        break;
                }
            }
    
    switch文の“var”はすべての状態をキャッチできます.
    を返します.

    プログラム.cs
            static void Main(string[] args)
            {
                var r = new {
                    Id = 0,
                    Name = "Hello"
                };
                Play((object)r);
            }
            private static void Play(object target)
            {
                switch(target)
                {
                    case RecordSample r:
                        Console.WriteLine($"Record Id: {r.Id} Name: {r.Name}");
                        break;
                    case var o when RecordSample.TryParse(o, out var r):
                        Console.WriteLine($"Property Id: {r!.Id} Name: {r!.Name}");
                        break;
                    default:
                        Console.WriteLine("Not found");
                        break;
                }
            }
    

    結果
    Property Id: 0 Name: Hello