將 Using Statement 重構成 Using() Function

栏目: ASP.NET · 发布时间: 6年前

内容简介:C# 有個著名的macOS High Sierra 10.13.6.NET Core 2.1

C# 有個著名的 using statement,對於實踐 IDisposable 的物件特別好用,但 using 是個 statement,在 Imperative 世界沒問題,但在 Functional 世界,statement 就類似 句點 ,讓我們無法繼續 Pipeline 或對其他 function 做 Compose,我們能否比照將 foreach statement 重構成 ForEach() function,也將 using statement 重構成 using() function 呢 ?

Version

macOS High Sierra 10.13.6

.NET Core 2.1

C# 7.2

F# 4.5

Rider 2018.1.4

C# 之 Using Statement

using System;
using System.IO;

namespace ConsoleApp
{
    public static class Program
    {
        public static void Main()
        {
            using (var streamReader = new StreamReader("TestFile.txt"))
            {
                var line = streamReader.ReadToEnd();
                Console.WriteLine(line);
                // Hello World
            }
        }
    }
}

StreamReader 是個典型實踐 IDisposable 的物件,所以在使用時都會使用 using statement 包起來,等離開 {} scope 時,自動呼叫 Dispose() 釋放 resource。

這些都是我們都習慣的 C#。

using 是 statement,在 Imperative 世界沒問題,反正程式碼都是一行一行循序執行。

但在 Functional 世界,我們要求 code 要 Pipeline,要 Compose,所以 FP 喜歡使用 expression,不喜歡 statement。

Statemet 就類似 句點 ,讓所有的 Pipeline 都中斷了。

其實仔細看 using statement,其實包含幾個部分:

  • Setup : 獲得 resource
  • Body : 執行 resource
  • Teardown : 釋放 resource

其中 using statement 就是幫我們做 teardown 部分。

因此我們可以自己寫一個 Using() function,將 setup 與 body 傳入 Using()

C# 之 Using() Function

using System.IO;
using static Functional.F;

namespace ConsoleApp
{
    public static class Program
    {
        public static void Main()
        {
            Using(new StreamReader("TestFile.txt"), ReadFile)
                .WriteLine();
                       
            string ReadFile(StreamReader streamReader) => streamReader.ReadToEnd();
        }
    }
}

10 行

Using(new StreamReader("TestFile.txt"), ReadFile)
	.WriteLine();

使用 Using() function,將 setup 傳入第一個參數,將 body 傳入第二個參數。

由於 ReadFile() 回傳為 string ,因此 Using() 也是回傳 string ,這樣就可以使用 Pipeline 方式 WriteLine() 直接印出。

13 行

string ReadFile(StreamReader streamReader) => streamReader.ReadToEnd();

Body 以 local function 定義。

至於 Using()WriteLine() 怎麼來的呢 ? 是我們自己寫的 Higher Order Function。

using System;

namespace Functional
{
    public static class F
    {
        public static R Using<TDisp, R>(TDisp disposable, Func<TDisp, R> f) where TDisp : IDisposable
        {
            using (disposable) return f(disposable);
        }

        public static void WriteLine(this string data)
        {
            Console.WriteLine(data);
        }
    }
}

第 7 行

public static R Using<TDisp, R>(TDisp disposable, Func<TDisp, R> f) where TDisp : IDisposable
{
    using (disposable) return f(disposable);
}

自己寫一個 Using() HOF,第一個參數傳入 IDisposable 物件,第二個參數傳入 body function。

12 行

public static void WriteLine(this string data)
{
    Console.WriteLine(data);
}

自己為 string 加上 WriteLine() Extension Method,這就就可以對 string 繼續 Pipeline 印出。

C# 為了讓 using 用起來更 FP,我們必須自己實作 Using()WriteLine() ,但在 Functional First 的 F#,除了提供 Imperative 的 use 外,也提供了 Functional 的 using() ,我們完全不用自己另外實作

F# 之 Use Bind

open System.IO

let readFromFile (fileName: string) = 
    use streamReader = new StreamReader(fileName)
    streamReader.ReadToEnd()
    
readFromFile "TestFile.txt"
|> printf "%A"

F# 之 use 類似於 let ,差別是 use 在離開 function 就會呼叫 Dispose() ,不需特別加上 {} 縮排一層。

由於 readFromFile() 回傳 string ,可以直接 Pipeline 接內建的 printf()

use 仍然是個 statement。

F# 之 Using() Function

open System.IO

let readFile (streamReader: StreamReader) =
    streamReader.ReadToEnd()

let readFromFile (fileName: string) =
    using(new StreamReader(fileName)) readFile 
    
readFromFile "TestFile.txt"
|> printf "%A"

第 6 行

let readFromFile (fileName: string) =
    using(new StreamReader(fileName)) readFile

改用 F# 內建的 using() ,第一個參數傳入 IDisposable 物件,第二個參數傳入 body function,其實跟自己用 C# 實作的 Using() 是一樣的。

第 3 行

let readFile (streamReader: StreamReader) =
    streamReader.ReadToEnd()

定義 body function。

由於 using()printf() 都是 F# 內建,因此我們就不必再自己實作了

Conclusion

  • 將 C# 由 using statement 改成 using() function,乍看之下意義不大;但若去看 F# 同時提供 use statement 與 using() function 時,就可看出 F# 的用心良苦,同時支援了 Imperative 與 Functional 兩種 paradigm
  • 由於 F# 每個 function 都是 composable,因此我們就不必再自已寫 WriteLine() 了,直接 printf() 就可以 pipeline 起來

Sample Code

  • C# : 完整的範例可以在我的 GitHub 上找到
  • F# : 完整的範例可以在我的 GitHub 上找到

Reference

Enrico Buonanno, Functional Programming in C#


以上所述就是小编给大家介绍的《將 Using Statement 重構成 Using() Function》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

About Face 3

About Face 3

Alan Cooper、Robert Reimann、David Cronin / John Wiley & Sons / 2007-5-15 / GBP 28.99

* The return of the authoritative bestseller includes all new content relevant to the popularization of how About Face maintains its relevance to new Web technologies such as AJAX and mobile platforms......一起来看看 《About Face 3》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具