iT邦幫忙

2022 iThome 鐵人賽

DAY 24
0

今天要介紹IObservable-IEnumerable-Task這三者的關係

IEnumerable

IEnumerable代表的是一組資料序列,而IObservable可以代表一個”可被觀察的資料序列”,可以觀察下面兩段code,在通過ToObservable()後可以將集合轉換,所以1與2印出來的結果是相同的。

var list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

// 1
list.Select(x => 10 * x).ToList().ForEach(Console.WriteLine); 

// 2
list.ToObservable().Select(x => 10 * x).Subscribe(Console.WriteLine); 

Task

這邊舉個例子,我知道天線寶寶在太陽出來的時候會說你好,但是我並不知道什麼時候會發生,所以我將天線寶寶說你好這個Task轉換成可以被觀察的事件,當事件發生的時候就會印出來讓我知道。

var teletubbiesSay = Task.FromResult("你好");
teletubbiesSay.ToObservable().Subscribe(Console.WriteLine);

組合

既然我知道了IObservable-IEnumerable-Task三者之間是有關係的的,並且三者都有monad的特性,那我們可以怎麼使用呢?假設我今天有一個名單(IEnumerable),並且可以透過第三方的API來得知名單上人物的真實身份

var nameList = new List<string> { "洛伊德", "約兒", "安妮亞" };
var roleDic = ImmutableDictionary<string, string>.Empty.Add("洛伊德", "黃昏").Add("約兒", "睡美人").Add("安妮亞", "實驗體007");

// map
var result = from n in nameList
			 select GetRoleAsync(n).Result;

// 如果希望用await
// var observable = nameList.Select(async n =>  await GetRole(n));

observable.ToObservable().Subscribe(Console.WriteLine);

Task<string> GetRoleAsync(string name) => Task.FromResult(roleDic[name]);

我可以直接透過Map到結果得到每個人的身份,但是這邊需要用到執行緒封鎖的方式取值,如果將.Result拿掉,或是改用await修飾詞,result的型別就會是IEnumerable<Task<string>>,說實話真的不好處裡,而我們總是希望能夠不使用執行緒封鎖(說實話想用Rx.net你還真的最好封鎖)。但IObservable-IEnumerable-Task是三位一體的monad,所以我可以用SelectMany輕易解決此事

var observable = 
    from n in nameList.ToObservable()
    from a in GetRoleAsync(n).ToObservable()
    select a;

observable.Subscribe(Console.WriteLine);

補充

在做這一章的時候踩到一個雷,在測試非同步的時候一直出bug,Test2一直印不出東西來

Test1().ToObservable().Subscribe(Console.WriteLine);
// 執行緒封鎖
Test2().ToObservable().Subscribe(Console.WriteLine);
// ...

async Task<string> Test1()
{
		Task.Delay(100).GetAwaiter().GetResulter();
		return "執行緒封鎖";
}

async Task<string> Test2()
{
		await Task.Delay(100);
		return "不封鎖";
}

後來發現Rx.net底層用的是封鎖的方法,所以Test2看到await控制權就轉移,然後主程式就結束了,永遠等不到結果……,為了解決問題GitHub Repo上有了一個新的資料夾AsyncRx.net,正式發布不知道還要等多久,詳細可以參考這篇issue


上一篇
Day23. Rx(1)
下一篇
Day25. Rx(3)
系列文
Functional Programming with C#30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言