Red Architectureã®èª¬æã®æåŸã®éšåã¯ããã«ãã¹ã¬ããå°çšã§ãã å
¬å¹³ãæãããã«ãã¯ã©ã¹vã®
åæããŒãžã§ã³ã¯æé©ãšã¯èŠãªãããŸãããçŸå®äžçã®ã¢ããªã±ãŒã·ã§ã³ã®éçºè
ãé¿ããããªãäž»èŠãªåé¡ã®1ã€ã解決ãããã®ã¯äœããªãããã§ãã çŸåšã®èšäºãå®å
šã«çè§£ããã«ã¯ã
ããã§Red Architectureã®æŠå¿µãçè§£ããå¿
èŠããã
ãŸã ã

ä»åŸã¯ãã¯ã©ã¹vã®å¶éãè¶
ããããšãªãããã«ãã¹ã¬ããã®ãã¹ãŠã®åé¡ã解決ã§ãããšèšããŸãã ããã«ãèŠãç®ãããã¯ããã«å°ãªã倿Žãè¡ããããã®çµæãå®å
šã«è§£æ±ºããããã«ãã¹ã¬ããã®åé¡ãå«ãã¯ã©ã¹vã³ãŒãã¯ã50è¡åŒ·ã§æ§æãããŸãïŒ ããã«ã
æåã®ããŒãã§èª¬æããã¯ã©ã¹vã®ããŒãžã§ã³ããããããããª50è¡ãæé©ã§ãã ãã®å Žåãã¹ã¬ããåæã®åé¡ã解決ããç¹å®ã®ã³ãŒãã¯20è¡ããããããŸããïŒ
ããã¹ãã®éçšã§ããã®èšäºã®æåŸã«ãã宿ããã¯ã©ã¹vãšãã¹ãã®ãªã¹ãããåã
ã®è¡ãè§£æããŸããRed Architectureã¯ã©ãã«é©çšã§ããŸããïŒ
ããã§
玹ä»ããäŸ
㯠ã
Red Architectureã®æŠå¿µå
šäœãšåæ§ã«ã
å¯èœãªãã¹ãŠã®èšèªãšãã©ãããã©ãŒã ã§äœ¿çšã§ããããã«æäŸãããŠããããšã匷調ããããšæã
ãŸã ã CïŒ/ Xamarinãš.NETãã©ãããã©ãŒã ã¯ãå人çãªå¥œã¿ã«åºã¥ããŠRed Architectureããã¢ã³ã¹ãã¬ãŒã·ã§ã³ããããã«éžã°ããŸããã
ã¯ã©ã¹vã®2ã€ã®ããªã¢ã³ã
ã¯ã©ã¹vã®2ã€ã®ããªã¢ã³ãããããŸãã æ©èœãš1çªç®ã®äœ¿ç𿹿³ãåã2çªç®ã®ãªãã·ã§ã³ã¯ãããè€éã«ãªããŸãã ãããããæšæºãã®CïŒ.NETç°å¢ã ãã§ãªããXamarinã®PCLç°å¢ã§ã䜿çšã§ããŸããã€ãŸãã3ã€ã®ãã©ãããã©ãŒã ïŒiOSãAndroidãWindows 10 MobileïŒã§ã®ã¢ãã€ã«éçºãæå³ããŸãã å®éãXamarinãã¬ãŒã ã¯ãŒã¯ã®PCLç°å¢ã§ã¯ã¹ã¬ããã»ãŒãã³ã¬ã¯ã·ã§ã³ã䜿çšã§ããªããããXamarin / PCLã®ã¯ã©ã¹vã®ããŒãžã§ã³ã«ã¯ãã¹ã¬ãããåæããããã®ã³ãŒããå€ãå«ãŸããŸãã ããã¯ããã®èšäºã§æ€èšããããšã§ããã¯ã©ã¹vã®ç°¡æããŒãžã§ã³ïŒãã®èšäºã®æåŸã«ãããŸãïŒã¯ããã«ãã¹ã¬ããã®åé¡ãšãã®è§£æ±ºæ¹æ³ãçè§£ããäžã§ããŸã䟡å€ããããŸããã
å°ãã®æé©å
ãŸããåºæ¬ã¯ã©ã¹ãåãé€ããã¯ã©ã¹vãèªçµŠèªè¶³ã«ããŸãã ä»ãŸã§äœ¿çšããŠããåºæ¬ã¯ã©ã¹ã®éç¥ã¡ã«ããºã ã¯å¿
èŠãããŸããã ç¶æ¿ãããã¡ã«ããºã ã§ã¯ããã«ãã¹ã¬ããã®åé¡ãæé©ãªæ¹æ³ã§è§£æ±ºããããšã¯ã§ããŸããã ãããã£ãŠã次ã¯ãã³ãã©ãŒé¢æ°ã«ã€ãã³ããéä¿¡ããŸãã
static Dictionary<k, HashSet<NotifyCollectionChangedEventHandler>> handlersMap = new Dictionary<k, HashSet<NotifyCollectionChangedEventHandler>>();
foreachã«ãŒãã®
AddïŒïŒã¡ãœããã§ãèŠçŽ ã
HashSet 'aãã
Listã«ã³ããŒããããã·ã¥ã»ããã§ã¯ãªãã·ãŒããå埩åŠçããŸãã handlersMap [key]åŒã«ãã£ãŠè¿ãããå€ã¯ãmïŒïŒãhïŒïŒãªã©ã®ãããªãã¯ç¶æ
倿Žã¡ãœããããã¢ã¯ã»ã¹å¯èœãªã°ããŒãã«å€æ°ã§ããããããããè¡ãå¿
èŠããããŸãããããã£ãŠãhandlersMap [key]åŒã«ãã£ãŠè¿ãããHashMapã¯AddïŒïŒã¡ãœããã§ã®å埩äžã«å¥ã®ã¹ã¬ããã«ãã£ãŠå€æŽãããŸããforeachå
ã®ã³ã¬ã¯ã·ã§ã³ã®å埩ãå®äºãããŸã§ããã®ïŒã³ã¬ã¯ã·ã§ã³ïŒå€æŽã¯çŠæ¢ãããŠãããããå®è¡æã«å®è¡ãããŸãã ããããã°ããŒãã«å€æ°ã§ã¯ãªããã°ããŒãã«HashSetã®èŠçŽ ãã³ããŒãããListãå埩ã§ã眮æãããçç±ã§ãã
ãããããã®ä¿è·ã¯ååã§ã¯ãããŸããã åŒã§
new List<NotifyCollectionChangedEventHandler>(handlersMap[key])
ã³ããŒæäœã¯ãhandlersMap [key]ã®å€ïŒããã·ã¥ã»ããïŒã«æé»çã«é©çšãããŸãã ã³ããŒæäœã®éå§ãšçµäºã®éã«ãä»ã®ã¹ã¬ãããã³ããŒãããããã·ã¥ã»ããã®èŠçŽ ã远å ãŸãã¯åé€ããããšãããšãããã¯ééããªãåé¡ãåŒãèµ·ãããŸãã ãããã£ãŠãforeachã®éå§çŽåã«ãã®ããã·ã¥ã«ããã¯ïŒMonitor.EnterïŒhandlersMap [key]ïŒïŒãèšå®ããŸãã
Monitor.Enter(handlersMap[key]); foreach (var handlr in new List<NotifyCollectionChangedEventHandler>(handlersMap[key])) {
ããªãªãŒã¹ãïŒMonitor.ExitïŒhandlersMap [ããŒ]ïŒïŒforeachã«ãŒãã«å
¥ã£ãçŽåŸã«ããã¯ãã
foreach (var handlr in new List<NotifyCollectionChangedEventHandler>(handlersMap[key])) { if (Monitor.IsEntered(handlersMap[key])) { Monitor.PulseAll(handlersMap[key]); Monitor.Exit(handlersMap[key]); }
Monitorãªããžã§ã¯ãã®ã«ãŒã«ã«åŸã£ãŠãEnterïŒïŒã®åŒã³åºãã®æ°ã¯ExitïŒïŒã®åŒã³åºãã®æ°ã«å¯Ÿå¿ããå¿
èŠããããããããã¯ãã€ã³ã¹ããŒã«ãããå Žåã«1ã€ã ããçµäºããããšã確èªããifãã§ãã¯ïŒMonitor.IsEnteredïŒhandlersMap [key]ïŒïŒããããŸãåãforeachã«ãŒãã®æåã®å埩ã®éå§æã è¡Monitor.ExitïŒhandlersMap [key]ïŒã®çŽåŸã«ãhaslers handlersMap [key]ãä»ã®ã¹ã¬ããã§åã³äœ¿çšå¯èœã«ãªããŸãã ãããã£ãŠãããã·ã¥ããã¯ãå¯èœãªæå°æéã«å¶éããŸãããã®å Žåãããã·ã¥ã¯æåéãäžæçã«ãããã¯ããããšèšããŸãã
foreachã«ãŒãã®çŽåŸã«ãããã¯è§£é€ã³ãŒãã®ç¹°ãè¿ãã衚瀺ãããŸãã
ãã®ã³ãŒãã¯ãforeachã«å埩ããªãå Žåã«å¿
èŠã§ããããã¯ãããŒã®1ã€ã«å¯ŸããŠã察å¿ããããã·ã¥ã»ããã«åäžã®ãã³ãã©ãŒããªãå Žåã«å¯èœã§ãã
次ã®ã³ãŒãã«ã¯è©³çްãªèª¬æãå¿
èŠã§ãã
lock(handlr) try {
å®éãRed Architectureã®æŠå¿µã§ã¯ãã¯ã©ã¹vã®å€éšã§äœæãããã¹ã¬ããã®åæãå¿
èŠãšãããªããžã§ã¯ãã¯ãã³ãã©ãŒé¢æ°ã®ã¿ã§ãã ãã³ãã©ãŒã颿°ãåŒã³åºãã³ãŒãã管çã§ããªãã£ãå Žåãåãã³ãã©ãŒã®ããã«ããã§ã³ã¹ãããå¿
èŠããããŸã
void OnEvent(object sender, NotifyCollectionChangedEventArgs e) { lock(OnEvent);
lockïŒïŒunlockïŒïŒè¡ã®éã«æçšãªã¡ãœããã³ãŒããé
眮ãããŠããããšã«æ³šæããŠãã ããã å€éšã®ãã³ãã©ãŒå
ã®ããŒã¿ã倿Žãããå ŽåãlockïŒïŒããã³unlockïŒïŒã远å ããå¿
èŠããããŸãã åæã«ããã®é¢æ°ã«å
¥ããããŒã¯ãæ··variablesãšããé åºã§å€éšå€æ°ã®å€ã倿Žããããã§ãã
ãããã代ããã«ãããã°ã©ã å
šäœã«1è¡ïŒããã¯ïŒhandlrïŒïŒã远å ããvã¯ã©ã¹å
ã§ãããå€éšã®äœãè§Šããã«è¡ããŸããïŒ vã¯ã©ã¹ã®å®è£
ã«ããã1ã€ã®ã¹ã¬ããã®ã¿ããã®ç¹å®ã®ãã³ãã©ãŒã«å
¥ãããšãä¿èšŒãããä»ã®ã¹ã¬ããã¯ããã¯ïŒããã³ãã©ãŒãïŒã«ãç«ã¡ãããã®äœæ¥ãå®äºãããŸã§åŸ
æ©ãããããã¹ã¬ããã®å®å
šæ§ãèããã«ä»»æã®æ°ã®ãã³ãã©ãŒé¢æ°ãäœæã§ããŸããããå
¥åããåã®ã¹ã¬ããã®ãã³ãã©ãŒã
foreachãforïŒ;;ïŒããã³ãã«ãã¹ã¬ãã
ãã¹ãã®ãªã¹ãïŒèšäºã®æåŸïŒã«ã¯ã2ã€ã®ã¹ã¬ããããã®ã¡ãœããã«å
¥ãããããã£ãŠforïŒ;;ïŒã«ãŒãã«å
¥ããšãã«forïŒ;;ïŒã«ãŒãã®åäœããã§ãã¯ããforeachTestïŒstring [] aïŒã¡ãœããããããŸãã 以äžã¯ããã®ã¡ãœããã®åºåã®å¯èœãªéšåã§ãã
// ...
ãïŒstring20
ãïŒstring21
ãïŒstring22
ãïŒastring38
ãïŒastring39
ãïŒstring23
ãïŒstring24
ãïŒastring40
ãïŒastring41
ãïŒstring25
ãïŒastring42
ãïŒstring26
ãïŒastring43
ãïŒastring44
ãïŒstring27
ãïŒastring45
ãïŒstring28
// ...
ãstringãè¡ãšãastringãè¡ã®åºåãæ··åšããŠããã«ãããããããåè¡ã®æ°å€ã®æ¥å°ŸèŸã¯é çªã«äžŠãã§ããŸãã åè¡ãåºåããããã«ãããŒã«ã«å€æ°iãçã«ãªããŸãã ãã®çµè«ã¯ãforïŒ;;ïŒãžã®2ã€ã®ã¹ã¬ããã®åæå
¥åãå®å
šã§ããããšã瀺åããŠããŸãã ãããããforïŒ;;ïŒæ§é ã®ãã¬ãŒã ã¯ãŒã¯ã§å®£èšããããã¹ãŠã®å€æ°ãããšãã°å€æ°int iã¯ãforïŒ;;ïŒã«å
¥ã£ãã¹ããªãŒã ã®ã¹ã¿ãã¯äžã«äœæãããŸãã ãã®ãããïŒ;;ïŒã®å
éšã§äœæããã倿°ãžã®ã¢ã¯ã»ã¹ã¯ããæåãåæãå¿
èŠãšããŸããããªããªãããããã¯ãã¹ã¿ãã¯ãäœæãããã¹ã¬ããã§ã®ã¿å©çšå¯èœã ããã§ãã ããã¯ãCïŒãš.NETãã©ãããã©ãŒã ã®å Žåã§ãã ä»ã®èšèªã§ã¯ãå¯èœæ§ã¯äœãã§ãããç°ãªãåäœãããå¯èœæ§ãããããããã®ãããªãã¹ãã¯äžèŠã§ã¯ãããŸããã
try ... catchã¯äŸå€ã§ã¯ãªãæšæºã§ã
try ... catchäžèŠããã®æ§é ã¯äžèŠã«æããŸãããéèŠã§ãã handlr.InvokeïŒïŒã®åŒã³åºãæã«ãhandlrãå®çŸ©ããããªããžã§ã¯ããç Žå£ãããç¶æ³ããç§ãã¡ãä¿è·ããããšãç®çãšããŠããŸãã ãªããžã§ã¯ãã®ç Žæ£ã¯ãè¡éã§ãã€ã§ãå¥ã®ã¹ã¬ãããŸãã¯ã¬ããŒãžã³ã¬ã¯ã¿ãŒã«ãã£ãŠå®è¡ã§ããŸãã
foreach (var handlr in new List<NotifyCollectionChangedEventHandler>(handlersMap[key]))
ãããŠ
handlr.Invoke();
catchãããã¯ã§ããäŸå€åŠçã§ã¯ããã³ãã©ãŒãnullïŒå逿žã¿ïŒãªããžã§ã¯ããåç
§ããŠãããã©ããã確èªãããã³ãã©ãŒãªã¹ãããåçŽã«åé€ããŸãã
lock (handlr) try { handlr.Invoke(key, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<KeyValuePair<k, object>>(){ new KeyValuePair<k, object>(key, o) })); #if __tests__ /* check modification of global collection of handlers for a key while iteration through its copy */ handlersMap[key].Add((object sender, NotifyCollectionChangedEventArgs e) => { }); #endif } catch (Exception e) { // because exception can be thrown inside handlr.Invoke(), but before handler was destroyied. if (ReferenceEquals(null,handlr) && e is NullReferenceException) // handler invalid, remove it m(handlr); else // exception in handler's body throw e; }
ã¯ã©ã¹vã®åæå
éçã³ã³ã¹ãã©ã¯ã¿ãŒã¯ãCïŒã®ç¹åŸŽã®1ã€ã§ãã çŽæ¥åŒã³åºãããšã¯ã§ããŸããã ãã®ã¯ã©ã¹ã®æåã®ãªããžã§ã¯ããäœæããåã«ãäžåºŠã ãèªåçã«åŒã³åºãããŸãã ããã䜿çšããŠhandlersMapãåæåããŸã-kã®ãã¹ãŠã®ããŒã«å¯ŸããŠãåããŒã®ãã³ãã©ãŒé¢æ°ãæ ŒçŽããããã®ç©ºã®HashSetã䜿çšããæºåãããŸãã ä»ã®èšèªã«éçã³ã³ã¹ãã©ã¯ã¿ãŒããªãå Žåããªããžã§ã¯ããåæåããã¡ãœãããé©ããŠããŸãã
static v() { foreach (ke in Enum.GetValues(typeof(k))) handlersMap[e] = new HashSet<NotifyCollectionChangedEventHandler>(); new Tests().run(); }
ã¹ã¬ããã®å®å
šã§ãªãã³ã¬ã¯ã·ã§ã³ãã©ããããïŒ
CïŒã¯ã©ã¹ã®HashSetã¯ãè€æ°ã®ã¹ã¬ããïŒã¹ã¬ããã»ãŒãã§ã¯ãªãïŒããã®å€æŽæã«åæãæäŸããªãããããã®ãªããžã§ã¯ãã®å€æŽãã€ãŸãèŠçŽ ã®åé€ãšè¿œå ãåæããå¿
èŠããããŸãã ãã®å Žåãã¯ã©ã¹vã®ã¡ãœããmïŒïŒãhïŒïŒã§èŠçŽ ãåé€/远å ããæäœã®çŽåã«ã1ã€ã®è¡ããã¯ïŒhandlersMap [key]ïŒã远å ããã ãã§ååã§ãã ãã®å ŽåããããŒããããã¯ãããªããžã§ã¯ãã¯ããã®ç¹å®ã®ããŒã«é¢é£ä»ããããHashMapãªããžã§ã¯ãã«ãªããŸãã ããã«ããã1ã€ã®ã¹ã¬ããã®ã¿ã§ãã®ç¹å®ã®ããã·ã¥ã»ããã倿Žã§ããŸãã
ãã«ãã¹ã¬ããã®å¯äœçš
ãã«ãã¹ã¬ããã®ãå¯äœçšãã®ããã€ãã«èšåãã䟡å€ããããŸãã ç¹ã«ããã³ãã©ãŒé¢æ°ã®ã³ãŒãã¯ãå Žåã«ãã£ãŠã¯ãã³ãã©ãŒé¢æ°ã®ããµãã¹ã¯ã©ã€ãè§£é€ãåŸã«ã€ãã³ããåä¿¡ããåŸã«åŒã³åºããããšããäºå®ã«åããŠæºåããå¿
èŠããããŸãã ã€ãŸããmïŒããŒããã³ãã©ãŒïŒãã³ãã©ãŒããã°ããïŒãããã1ç§æªæºïŒåŒã³åºããåŸã§ãåŒã³åºãããšãã§ããŸãã ããã¯ãmïŒïŒã¡ãœããã§handlersMap [key] .RemoveïŒhandlerïŒãåŒã³åºãããšãã«ããã®ãã³ãã©ãŒãforeachè¡ã®å¥ã®ã¹ã¬ããã«ãã£ãŠæ¢ã«ã³ããŒãããŠããå¯èœæ§ãããããã§ãïŒæ°ãããªã¹ãã®var handlrïŒhandlersMap [key]ïŒïŒ ãããã³mïŒïŒã¡ãœããã§åé€ãããåŸãã¯ã©ã¹vã®AddïŒïŒã¡ãœããã§åŒã³åºãããŸãã
è€éãªåé¡ã解決ããç°¡åãªã«ãŒã«
çµè«ãšããŠãç§ã¯å€åãªéçºè
ã§ãããããããã¯ã®äœ¿çšã«é¢ããåæã«éåããªããšããäºå®ã«æ³šæãåèµ·ããããšæããŸãã ç¹ã«ããã®ãããªå¥çŽã¯ããã®ããŒãžã®
docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statementã®åèã»ã¯ã·ã§ã³ã«ãªã¹ããããŠããŸãã CïŒã ãã§ãªãããã¹ãŠã®èšèªã«å
±éã§ãã ãããã®å¥çŽã®æ¬è³ªã¯æ¬¡ã®ãšããã§ãã
- ãããªãã¯åãããã¯ã®ãªããžã§ã¯ããšããŠäœ¿çšããªãã§ãã ããã
ããã¯ã«ã¯2çš®é¡ã®ãªããžã§ã¯ãã䜿çšããäž¡æ¹ãšããã©ã€ããŒãã§ãã æåã®ã¿ã€ãã¯ãã¯ã©ã¹vã«ãã©ã€ããŒããªHashSetãªããžã§ã¯ãã§ãã 2çªç®ã®åã¯ã颿°ãã³ãã©ãŒåã®ãªããžã§ã¯ãã§ãã 颿°ãã³ãã©ã¯ããããã宣èšãããããã䜿çšããŠã€ãã³ããåä¿¡ãããã¹ãŠã®ãªããžã§ã¯ãã§ãã©ã€ããŒããšããŠå®£èšãããŸãã Red Architectureã®å Žåãvã¯ã©ã¹ã®ã¿ããã³ãã©ãŒãçŽæ¥åŒã³åºãå¿
èŠãããããã以å€ã¯äœãåŒã³åºããŸããã
ãªã¹ã
以äžã¯ãvã¯ã©ã¹ãšTestsã¯ã©ã¹ã®å®æããã³ãŒãã§ãã CïŒã§ã¯ãããããã³ããŒããŠçŽæ¥äœ¿çšã§ããŸãã ãã®ã³ãŒããä»ã®èšèªã«ç¿»èš³ããããšã¯ãããªãã«ãšã£ãŠå°ããªæ¥œããä»äºã«ãªããŸãã
以äžã¯ãããŠãããŒãµã«ãã¯ã©ã¹vã®ã³ãŒãã§ããããã¯ãXamarin / CïŒãã©ãããã©ãŒã ã«åºã¥ãã¢ãã€ã«ã¢ããªã±ãŒã·ã§ã³ãããžã§ã¯ãã§ã䜿çšã§ããŸãã
using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Threading; namespace Common { public enum k {OnMessageEdit, MessageEdit, MessageReply, Unused, MessageSendProgress, OnMessageSendProgress, OnIsTyping, IsTyping, MessageSend, JoinRoom, OnMessageReceived, OnlineStatus, OnUpdateUserOnlineStatus } public class v { static Dictionary<k, HashSet<NotifyCollectionChangedEventHandler>> handlersMap = new Dictionary<k, HashSet<NotifyCollectionChangedEventHandler>>(); public static void h(k[] keys, NotifyCollectionChangedEventHandler handler) { foreach (var key in keys) lock(handlersMap[key]) handlersMap[key].Add(handler); } public static void m(NotifyCollectionChangedEventHandler handler) { foreach (k key in Enum.GetValues(typeof(k))) lock(handlersMap[key]) handlersMap[key].Remove(handler); } public static void Add(k key, object o) { Monitor.Enter(handlersMap[key]); foreach (var handlr in new List<NotifyCollectionChangedEventHandler>(handlersMap[key])) { if (Monitor.IsEntered(handlersMap[key])) { Monitor.PulseAll(handlersMap[key]); Monitor.Exit(handlersMap[key]); } lock (handlr) try { handlr.Invoke(key, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<KeyValuePair<k, object>>(){ new KeyValuePair<k, object>(key, o) })); #if __tests__ /* check modification of global collection of handlers for a key while iteration through its copy */ handlersMap[key].Add((object sender, NotifyCollectionChangedEventArgs e) => { }); #endif } catch (Exception e) { // because exception can be thrown inside handlr.Invoke(), but before handler was destroyied. if (ReferenceEquals(null,handlr) && e is NullReferenceException) // handler invalid, remove it m(handlr); else // exception in handler's body throw e; } } if (Monitor.IsEntered(handlersMap[key])) { Monitor.PulseAll(handlersMap[key]); Monitor.Exit(handlersMap[key]); } } static v() { foreach (ke in Enum.GetValues(typeof(k))) handlersMap[e] = new HashSet<NotifyCollectionChangedEventHandler>(); new Tests().run(); } } }
以äžã¯ããæšæºãCïŒ.NETãã©ãããã©ãŒã ã§äœ¿çšã§ãããåçŽåããããã¯ã©ã¹vã®ã³ãŒãã§ãã ããŠãããŒãµã«ãã«ãŠã³ã¿ãŒããŒããšã®å¯äžã®éãã¯ãHashMapã®ä»£ããã«ConcurrentBagã³ã¬ã¯ã·ã§ã³ã䜿çšããŠããããšã§ããHashMapã¯ãèªåã«ã¢ã¯ã»ã¹ãããšãã«ããã«äœ¿çšã§ãããããŒã®åæãæäŸããã¿ã€ãã§ãã HashSetã®ä»£ããã«ConcurrentBagã䜿çšãããšãã¹ã¬ãããåæããã³ãŒãã®ã»ãšãã©ãã¯ã©ã¹vããåé€ã§ããŸãã
using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Collections.Concurrent; using System.Threading; namespace Common { public enum k { OnMessageEdit, MessageEdit, MessageReply, Unused, MessageSendProgress, OnMessageSendProgress, OnIsTyping, IsTyping, MessageSend, JoinRoom, OnMessageReceived, OnlineStatus, OnUpdateUserOnlineStatus } public class v { static Dictionary<k, ConcurrentBag<NotifyCollectionChangedEventHandler>> handlersMap = new Dictionary<k, ConcurrentBag<NotifyCollectionChangedEventHandler>>(); public static void h(k[] keys, NotifyCollectionChangedEventHandler handler) { foreach (var key in keys) handlersMap[key].Add(handler); } public static void m(NotifyCollectionChangedEventHandler handler) { foreach (k key in Enum.GetValues(typeof(k))) handlersMap[key].Remove(handler); } public static void Add(k key, object o) { foreach (var handlr in new List<NotifyCollectionChangedEventHandler>(handlersMap[key])) { lock (handlr) try { handlr.Invoke(key, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, new List<KeyValuePair<k, object>>(){ new KeyValuePair<k, object>(key, o) })); #if __tests__ /* check modification of global collection of handlers for a key while iteration through its copy */ handlersMap[key].Add((object sender, NotifyCollectionChangedEventArgs e) => { }); #endif } catch (Exception e) { // because exception can be thrown inside handlr.Invoke(), but before handler was destroyied. if (ReferenceEquals(null,handlr) && e is NullReferenceException) // handler invalid, remove it m(handlr); else // exception in handler's body throw e; } } } static v() { foreach (ke in Enum.GetValues(typeof(k))) handlersMap[e] = new ConcurrentBag<NotifyCollectionChangedEventHandler>(); new Tests().run(); } } }
以äžã«ãTestsã¯ã©ã¹ã®ã³ãŒãã瀺ããŸãããã®ã¯ã©ã¹ã¯ãvã®ãã«ãã¹ã¬ãã䜿çšãšãã³ãã©ãŒé¢æ°ããã¹ãããŸãã ã³ã¡ã³ãã«æ³šæããŠãã ããã 圌ãã¯ãã¹ããšãã¹ãã³ãŒããã©ã®ããã«æ©èœãããã«ã€ããŠå€ãã®æçšãªæ
å ±ãæã£ãŠããŸãã
using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Threading.Tasks; using System.Diagnostics; using System.Linq; namespace ChatClient.Core.Common { class DeadObject { void OnEvent(object sender, NotifyCollectionChangedEventArgs e) { var newItem = (KeyValuePair<k, object>)e.NewItems[0]; Debug.WriteLine(String.Format("~ OnEvent() of dead object: key: {0} value: {1}", newItem.Key.ToString(), newItem.Value)); } public DeadObject() { vh(new k[] { k.OnlineStatus }, OnEvent); } ~DeadObject() {
ãã³ãã©ãŒé¢æ°ãç»é²ããã³ãŒããšããã®ãããªã¯ã©ã¹vã®ãã³ãã©ãŒé¢æ°èªäœã¯ã次ã®ããã«ãªããŸãã
ãã³ãã©ãŒæ©èœç»é²ã³ãŒã
ãã³ãã©ãŒæ©èœã³ãŒã
void OnEvent(object sender, NotifyCollectionChangedEventArgs e) { var newItem = (KeyValuePair<k, object>)e.NewItems[0]; Debug.Write("~ OnEvent(): key {0} value {1}", newItem.Key.ToString(), newItem.Value); }
Red Architectureã®äžè¬çãªèª¬æã¯
ãã¡ãã§ãã