C#委派練習


一直以來C#委派的語法總是很難搞懂,有一天寫一寫javascript的callback,突然感覺好像就是一樣的東西,似乎也沒那麼難,剛好有時間就找找範例來練習一下

從 CSV 文字檔中讀取紀錄,然後轉成 dto 進行其他操作

  • 方法 A:從檔案中取得資料,逐行執行某些行為
  • 方法 B:將文字轉換為 DTO 實體

為了不要讓某些事情的程式碼寫死在方法 A 裡面,具體的行為應從外部傳入給方法 A,所以透過委派的方式來做

private static void Main(string[] args)
{
    // 先宣告一個委派,輸入為字串,輸出是自訂的DTO物件,具體的方法則是定義在ConvertStrToDto
    Func<string, OutBoundUserCsv> myHandler = ConvertStrToDto;
    ReadCsvFile(myHandler);
    Console.ReadKey();
}

private static OutBoundUserCsv ConvertStrToDto(string source)
{
    // 將原始字串切割為陣列後逐一填入entity
    var d = source.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
    return new OutBoundUserCsv()
    {
        UserId = d[0],
        UserName = d[1]
    };
}

private static void ReadCsvFile(Func<string, OutBoundUserCsv> myHandler)
{
    // 透過StreamReader讀取檔案,否則檔案很大的話會拖垮系統
    using (var reader = new StreamReader("Input.txt"))
    {
        while (!reader.EndOfStream)
        {
            var line = reader.ReadLine();
            var usr = myHandler.Invoke(line);
            Console.WriteLine($"UserId:[{usr.UserId}] Name:[{usr.UserName}] ");
        }
    }
}

當然不要重複造輪子,所以其實 CSV 檔案的操作可以考慮使用FileHelpers 之類的套件來處理,這邊只是為了練習一下委派的用法來示例

Sample Code:GitHub

測試連線資料庫的數據

想要測試在不同的連線環境(固網、WIFI、VPN…Etc)之下,連線資料庫的速度

所以寫了這個小程式,還挺適合用委派的

internal class Program
{
    public static void Main(string[] args)
    {
        const int times = 100;
        var items = new Dictionary<string, Func<long>>
        {
            {"MsSql", MsSql},
            {"MariaDB", MariaDb},
            {"Oracle", Oracle},
        };
        foreach (var item in items)
        {
            PrintResult(LoopWorks(item.Value, times), item.Key);
        }
    }

    private static void PrintResult((long, decimal, int) job, string title)
    {
        Console.WriteLine($"{title}    執行 {job.Item3} 次資料存取,總計花費 {job.Item1:N1} ms,平均 {job.Item2} ms");
    }

    private static (long, decimal, int) LoopWorks(Func<long> works, int times)
    {
        long total = 0;
        for (var i = 1; i <= times; i++)
        {
            var speed = works.Invoke();
            total += speed;
        }

        return (total, Math.Round((decimal) total / times, 2), times);
    }

    private static long MsSql()
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        var source = new MsSqlAdapter().GetTestData();
        stopwatch.Stop();
        return stopwatch.ElapsedMilliseconds;
    }

    private static long MariaDb()
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        var source = new MariaDbAdapter().GetTestData();
        stopwatch.Stop();
        return stopwatch.ElapsedMilliseconds;
    }

    private static long Oracle()
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();
        var source = new OracleAdapter().GetTestData();
        stopwatch.Stop();
        return stopwatch.ElapsedMilliseconds;
    }
}