一個對象A,但願它的某些狀態在發生改變時通知到B(或C、D),
常見的作法是在A中定義一個事件(或直接用委託),當狀態改變時A去觸發這個事件。而B直接訂閱這個事件 asp.net
這種設計有點問題
B因爲要訂閱A的事件,因此B得徹底引用A,其實有時候不必,由於我只關心A的狀態變化而已
狀態變動通知這種場景不少,有沒有更通用的方式呢?異步
有個誰說的碰到問題加個中間層就解決了,若是解決不了就再加一層函數
A和B都引用ChangeToken,
B向ChangeToken註冊一個委託說:未來你有變化時回調我這個委託
當A的狀態變化時會調用ChangeToken的一個方法,這個方法內部就會去觸發執行B以前塞進去的委託
此時好比有組件C、D、E..都關心A的狀態變化,也能夠引用ChangeToken,並向其註冊本身的委託
這樣ChangeToken能夠做爲一個通用組件,在不少須要更改通知是場景中使用,如:asp.net core的配置系統、終結點路由、 ....學習
微軟定義了一個IChangeToken
HasChanged:表示當前這個ChangeToken是否變化過了
ActiveChangeCallbacks:當 A觸發ChangeToken發生變化時是否主動回調B塞進來的委託
RegisterChangeCallback(Action<object> callback, object state):提供一個方法,容許調用方塞入委託,B就是調用這個方法向ChangeToken塞入委託的。有一種狀況是B但願在塞入委託的同時附帶一個狀態對象,未來委託被執行時這個狀態對象做爲執行委託的參數this
CancellationChangeToken是一個用的比較多的實現類,它包含一個CancellationToken屬性,這個屬性是經過構造函數來初始化的(CancellationTokenSource、CancellationToken自行查詢相關資料),
簡化的源碼以下:spa
1 public class CancellationChangeToken : IChangeToken 2 { 3 public CancellationChangeToken(CancellationToken cancellationToken) 4 { 5 Token = cancellationToken; 6 } 7 8 public bool ActiveChangeCallbacks { get; private set; } = true; 9 10 public bool HasChanged => Token.IsCancellationRequested; 11 12 private CancellationToken Token { get; } 13 14 public IDisposable RegisterChangeCallback(Action<object> callback, object state) 15 { 16 return Token.Register(callback, state); 17 } 18 }
由於CancellationToken自然的已經現了IChangeToken,所以CancellationChangeToken只是對CancellationToken的包裝。那爲啥不直接讓CancellationToken實現IChangeToken呢?我感受是設計意圖不一樣,CancellationToken設計時主要是考慮應用在取消異步操做這件事上的,只是碰巧取消異步操做與更改通知設計思路是類似的,因此纔出現CancellationChangeToken.net
其它的實現類沒去研究過,可是隻要你對這種設計思路理解了,碰到其它實現類應該看看就明白了設計
下面咱們使用CancellationChangeToken來完成上面的A、B類,A類狀態變化時 通知到B類(其實就是執行B類忘ChangeToken中塞入的委託),完整源碼以下:code
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Console.OutputEncoding = Encoding.UTF8; 6 CancellationTokenSource cts = new CancellationTokenSource(); 7 CancellationChangeToken cct = new CancellationChangeToken(cts.Token); 8 var a = new A(cts); 9 var b = new B(cct); 10 Console.ReadKey(); 11 } 12 } 13 14 public class A 15 { 16 CancellationTokenSource _cts; 17 public A(CancellationTokenSource cts) 18 { 19 this._cts = cts; 20 Task.Run(() => 21 { 22 Task.Delay(2000).Wait(); 23 Console.WriteLine("模擬觸發更改通知"); 24 _cts.Cancel(); 25 }); 26 } 27 } 28 public class B 29 { 30 public B(CancellationChangeToken cct) { 31 object testState = 1; 32 cct.RegisterChangeCallback(obj => { 33 //未來cct檢測到變化時此委託會被執行 34 //obj是註冊委託是傳遞進來的參數,就是這裏的testState 35 Console.WriteLine($"狀態變化了,狀態值{obj}"); 36 }, testState); 37 } 38 }
上面只是演示IChangeToken的思路,asp.net core中源碼的應用時一般是在A中提供一個返回IChangeToken的方法對象
上面的方式只能變動通知一次,下面能夠永遠監控
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Console.OutputEncoding = Encoding.UTF8; 6 var a = new A(); 7 //實現無限監控狀態變化。OnChange有兩個委託類型的參數,咱們分別稱爲委託1和委託2 8 ChangeToken.OnChange(() => a.CreateChangeToken(), () => Console.WriteLine("a狀態變化了")); 9 Console.ReadKey(); 10 } 11 } 12 13 public class A 14 { 15 CancellationTokenSource _cts; 16 public A() 17 { 18 Task.Run(() => 19 { 20 while (true) 21 { 22 Task.Delay(2000).Wait(); 23 Console.WriteLine("模擬兩秒一次觸發一次狀態修改通知"); 24 this._cts.Cancel(); 25 } 26 }); 27 } 28 29 public IChangeToken CreateChangeToken() { 30 _cts = new CancellationTokenSource(); 31 return new CancellationChangeToken(_cts.Token); 32 } 33 }
重點是這句:ChangeToken.OnChange(() => a.CreateChangeToken(), () => Console.WriteLine("a狀態變化了"));
OnChange有兩個委託類型的參數,咱們分別稱爲委託1和委託2,當a的狀態變化後會執行委託2,以後會執行委託1,當a狀態又變化時又會執行委託2,以後執行委託1,如此往復實現無限監控
這是今天學習的內容,可能理解得不是很準確,僅供參考...