--- title: Expression in CSharp # 標題 description: Expression in CSharp # 描述 image: # 封面 tags: # 內部標籤 robots: index, nofollow # [no]index, [no]follow lang: zh # language dir: ltr # left to right or right to left breaks: # newline style GA: UA-168653916-1 # google analysis disqus: hackmd slideOptions: transition: fade # https://revealjs.com/transitions/ theme: back --- # Expression in C# ## 前言 最近我的 youtube 推薦影片中出現了一堆關於 C# 的 Expression 教學影片 小弟我對於 Expression 也算是小有研究 所以想說也來寫一些關於 Expression 的文章 但教學在網路上已經很多 不太想在寫重複的東西 所以 這篇我會分享關於 Expression 與我之間的一些事情 ## 什麼是 Expression 這裡簡單介紹```Expression``` 對於已經了解的可以跳過這段 ```Expression``` 在 C# 是指方法的[抽象語法樹(AST)](AST) 這是一個足以完整描述我們所寫下的方法的一個具有[不變性](Immutable)樹狀結構 而 ```Expression``` 與 ```Method``` 的關係 就如同 ```Type``` 與 ```Object``` 的關係 並且就像是我們可以在運行時透過 ```Type``` 來建立 ```Object``` 我們也可以在運行時 透過 ```Expression``` 來建立 ```Method``` 不過建立 ```Method``` 其實並不是一個 Best Practice 所以 通常比較好的應用 大多都不是建立 ```Method``` 而是如同我們使用 ```Type``` 上的資訊來達到我們的目的 後面也會介紹幾個用 ```Expression``` 而不是建立 ```Method``` 來達到目的的案例 ## Expression And Me ### 在認識 Expression 之前 早期如果要做一些泛用的東西 通常都會使用 Reflection(反射) 也就是直接透過 Type 來調用指定的 Method 或 Property 或是使用 Activator.CreateInstance 來建立物件 但眾所皆知的這幾個作法具有很嚴重的效能問題 如果想要解決這種效能問題 就得一下跳到[MSIL](MSIL) 這是一個對於即使接觸C#一陣子的人都是極為痛苦的一件事情 直到我發現 Expression 的存在改變了這一切 --- ### Object Member Accessor 我想這應該是很多擅長 Expression 的人的起點 就是可以任意存取物件的成員或是執行方法 這個東西的作法只用了足夠簡單的語法就實現了高效率的存取行為 而且可以讓我開始了解 Expression 可以做到更多的事情 我可以不用去理解與撰寫 [MSIL](MSIL) 而且以更貼近我們語法的指令來自由建構動態的方法 這導致有好一陣子我也成為了 Expression 粉 什麼事情都覺得 Expression 可以解決 ~~每個人都會有年少輕狂的時候~~ 甚至至今 Object Member Accessor 仍留在我常用的程式庫中 直到最終系統根本用不到這玩意 才會將他移除 [Object Member Accessor 程式碼傳送門](https://gist.github.com/dcvsling/5a052615e068e5a8651400350066b911) #### 泛用不代表就得用這種方式來存取 其實越寫到後面越發現 我們有很多的方法來繞過這樣的硬式存取 因為每一個動態做法都會造成系統的不可預測(或不易測試) 而從閱讀其他的程式庫以及設計模式 等等的技術內容發覺 我們可以透過"設計"我們的系統來迴避掉這種硬式存取 一個很典型的案例就是 我們可以透過抽象層的專案與實作層的專案及介面 讓我們迴避掉透過動態加載的組件中 建立我們需要的物件甚至運行其方法 案例可以參考[黑暗執行續大大近期的文章](https://blog.darkthread.net/blog/aspnet-auto-dll-type-discovery/?fbclid=IwAR0HCktnt4-dfM_x5i0lyFvBdD6cVVLrV_CGBwbhxPy7dTfqcSyt9eMfP9U)前半段存取 assembly 的用法 --- ### Entity Framework Query (以下簡稱 EF) 在我對於 Expression 有些許了解之後 我開始注意到 原來 EF 的查詢語法參數原來是 Expression 進而打開了我對於 EF 是如何轉為 SQL 語法 前一陣子我甚至寫了一個簡單的功能 讓 EF 的查詢可以用一個Json結構反序列化後進行轉換變成一個查詢 這樣做的目的是為了提供複雜查詢時的解決方案的一部分 [儲存庫傳送門](https://github.com/dcvsling/ExpressionForEF) 不過該專案當初是為了向某人證實 我們並不需要真的將Expression變成 Method 來實現我們的需求 以及裡面運用的技術不只有 Expression 再加上我沒寫註解 所以看不懂也不用太在意 如果對這個東西有興趣想討論的歡迎私下找我討論 #### Expression 真正的應用方式並不是轉為 Method 在看過 EF 的用法之後簡直就是開了一扇全新的大門 因為這表示可以透過LINQ的語法來轉譯成別種行為 甚至別種語言 而 System.Linq.Expressions 也提供了非常完整的功能 讓你可以更輕易地去解析轉換這些行為 而同類型的套件還有像是 Moq --- ### 受限於語言而無法或難以實現的困境 C# 其實已經可以做非常多的事情 每一種語言勢必都會受限於他自己的一些特性 而有時候可能會受限於這樣的限制 導致我們期望的做法難以或無法實現 而這件事情是我最常以 Expression 來解決困境 ~~說最常也就那麼一次 畢竟碰上的機率很低~~ 什麼是語言限制 例如之前提過 TypeScript 可以對於泛型如果帶入陣列型別 可以對於陣列每一個型別做明確對應這件事情 在 C# 至少到目前為止是完全不可能 所以導致 C# 在做像是 Action 和 Func 這樣的委派時 採用 code generate 的方式盡可能羅列一定範圍的實作 Expression 也可以做到這樣的事情 不過 Expression 的結果其實跟羅列那些可能性是一樣的 而且 Expression 的結果是在 runtime 不是在開發過程 所以 SDK 才會採用 羅列的方式來進行 致於我那次是如何使用的 我就不再這裡提及 而且那是為了因應開發時的需求的臨時作法 並且我也告訴對方那玩意允許的情況下最後還是拿掉比較好 也告訴他們要怎麼從當下的程式碼轉成大家常見的模式 ~~當然我當初也有為了讓他易於轉換而特別設計過~~ #### Simple vs Easy 雖然我不知道每個人在面對這樣的困境時是如何做的 Expression 某種程度上是一個非常直接的 Solution 一個具有難度的困境 其解決方案勢必是複雜的 當然我們可以把 code 寫得很 easy 但是勢必會在其他地方消耗更多的時間與精力 或是隱藏了更多的理論知識在這段程式碼的背後 所以 我相信每個寫這種code的人都勢必有她的難處 而我們能做的只有在把程式碼交出去之前將他[close](OCP) 以減少後續的人的麻煩 因為或許在當下這是難解的 隨著時間進展 我們可能會想到更好的做法 或是我們可能可以不再需要這樣做 所以在困難的事情上所做的複雜解決方案 我個人覺得 除了要能用之外 還要 simple install, simple use ,simple remove 藉此彌補其複雜度 以及 實現 [OCP](OCP) ## 結語 如果你是一個常用 Type 或是常常使用 GetType 的人 Expression 是真心推薦可以好好研究一番 這兩個東西是一樣的 至於如果你遇到必須接收到一份包含 Expression 的code 而你卻完全看不懂其中在做什麼的人 與其花時間抗議看不懂 不如趁機好好問對方它是怎麼運作的 我認為寫下這樣的程式碼的人本來就應該要為此負責 而我也是如此在付諸實行 如果那個人跑了 終究還是得要自己面對他 抱怨不會讓那些語法在做什麼 但貼到網路上或是開始學習 絕對可以讓你站上更好的位置 因為抱怨在老闆和主管面前沒有解決問題 而學習並且維護別人避之唯恐不及的東西才是老闆與主管想要的人 ~~如果大家都用最基本的東西在寫~~ ~~沒有設計 沒有規劃 正在抱怨的你能想像~~ ~~一堆強者正在搶你的飯碗 你搶的贏嗎? XD~~ # 連結 [AST](https://zh.wikipedia.org/wiki/%E6%8A%BD%E8%B1%A1%E8%AA%9E%E6%B3%95%E6%A8%B9) [Immutable](https://zh.wikipedia.org/wiki/%E4%B8%8D%E5%8F%AF%E8%AE%8A%E7%89%A9%E4%BB%B6) [MSIL](https://zh.wikipedia.org/wiki/%E9%80%9A%E7%94%A8%E4%B8%AD%E9%97%B4%E8%AF%AD%E8%A8%80) [OCP](https://zh.wikipedia.org/wiki/%E5%BC%80%E9%97%AD%E5%8E%9F%E5%88%99) <style> /*--------------- view ---------------*/ body[style], body[style*="background-color: white;"] { background-color: #1e1e1e !important; } body { color: #abb2bf; } .ui-view-area, .markdown-body, .ui-content { background: #1e1e1e; color: #abb2bf; } h1, h2, h3, h4, h5, h6, p { color: #ddd; } hr { border-color: #6d6d6d; } /* form */ .form-control { background: #333; color: #fff; } .form-control::placeholder, .form-control::-webkit-input-placeholder, .form-control:-moz-placeholder, .form-control::-moz-placeholder, .form-control:-ms-input-placeholder { color: #eee; } /*--------------- navbar ---------------*/ .header { background-color: #0e0e0e; border-color: #0e0e0e; } .navbar { background-color: #0e0e0e; border-color: #0e0e0e; } .navbar a { color: #eee !important; } .navbar .btn-group label { background-color: #0e0e0e; color: #eee; border-color: #555; } .navbar .btn-group label.btn-default:focus, .navbar .btn-group label.btn-default:hover { background-color: #2a2a2a; color: #eee; border-color: #555; } .navbar .btn-group label.active { background-color: #555; color: #eee; border-color: #555; } .navbar .btn-group label.active:focus, .navbar .btn-group label.active:hover { background-color: #555; color: #eee; border-color: #555; } .navbar-default .btn-link:focus, .navbar-default .btn-link:hover { color: #eee; } .navbar-default .navbar-nav>.open>a, .navbar-default .navbar-nav>.open>a:focus, .navbar-default .navbar-nav>.open>a:hover { background-color: #555; } .dropdown-header { color: #aaa; } .dropdown-menu { background-color: #222; border: 1px solid #555; border-top: none; } .dropdown-menu>li>a { color: #eee; } .dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover { background-color: #555555; color: #eee; } .dropdown-menu .divider { background-color: #555; } .header .open .dropdown-menu { background-color: #202020; } .navbar .announcement-popover { background: #4F4F4F; } .navbar .announcement-popover .announcement-popover-header { background: #2e2e2e; border-bottom: 1px solid #2e2e2e; } .navbar .announcement-popover .announcement-popover-body { background: #4F4F4F; color: #eee; } .navbar .announcement-popover .announcement-popover-footer { background: #4F4F4F; } .navbar .announcement-area .caption.inverse { color: #eee; } .label-warning { background-color: #ffc107; color: #212529; } /*--------------- history / recent ---------------*/ .list.row-layout li .item { border-color: #696c7d; } .list.row-layout li:nth-last-of-type(1) .item { border-bottom: none; } .list li .item { background: #1c1c1c; } .list li:hover .item, .list li:focus .item { background: #404040; } .list li .item h4 { color: #fff; } .list li p { color: #ccc; } .list li p i { font-style: normal; } .list li .item .content .tags span { background: #555; } .list li .item.wide .content .title a, .list li .item.wide .content .title a:focus, .list li .item.wide .content .title a:hover { color: #ddd; } .ui-item { color: #fff; opacity: 0.7; } .ui-item:hover, .ui-item:focus { opacity: 1; color: #fff; } .list li .item.wide hr { border-color: #6d6d6d; } .overview-widget-group .btn, .multi-select-dropdown-menu .ui-dropdown-label, .multi-select-dropdown-menu .dropdown-options, .form-control { border-color: #6d6d6d; } .multi-select-dropdown-menu .dropdown-options .ui-option:hover { background-color: #4d4d4d; color: #eee; } #overview-control-form #overview-keyword-input-container .select2-container { background-color: #3e4045 !important; } #overview-control-form #overview-keyword-input-container .select2-container .select2-choices { background-color: #3e4045; } .search { background-color: #3e4045; color: #eee; } .btn.btn-gray { background: #1b1b1b; } .btn.btn-gray:hover { background: #4d4d4d; color: #eee; } .search::placeholder, .search::-webkit-input-placeholder, .search:-moz-placeholder, .search::-moz-placeholder, .search:-ms-input-placeholder { color: #eee; } .btn.btn-gray { border-color: #6d6d6d; background: #333; color: #eee; } .select2-default { color: #eee !important; } .select2-results .select2-highlighted { background: #4d4d4d; color: #eee; } .select2-container-multi .select2-choices { background: #3e4045; } .select2-container-multi .select2-choices .select2-search-choice { background: #131313; color: #eee; border-color: #555; box-shadow: none; } .btn-default, .btn-default:focus { color: #eee; background-color: #2e2e2e; border-color: #6a6a6a; } .btn-default.active.focus, .btn-default.active:focus, .btn-default.active:hover, .btn-default:active.focus, .btn-default:active:focus, .btn-default:active:hover, .open>.dropdown-toggle.btn-default.focus, .open>.dropdown-toggle.btn-default:focus, .open>.dropdown-toggle.btn-default:hover { background: #737373; } .btn-default:hover { color: #fff; background-color: #7d7d7d; border-color: #6a6a6a; } .overview-widget-group .btn.active { background-color: #6a6a6a; color: #eee; } .overview-widget-group .btn:hover { background-color: #7d7d7d; color: #eee; border-color: #636363; } .overview-widget-group .slider.round { border-color: #ccc; } .overview-widget-group .slider.round:before { border-color: #ccc; } .overview-widget-group input:checked+.slider { background-color: #ccc; } .ui-category-description-icon a { color: #eee; } .item .ui-history-pin.active { color: #f00; } .ui-history-close { color: #eee; opacity: 0.5; } .pagination>li>a, .pagination>li>span { color: #eee; background-color: #2e2e2e; border-color: #6a6a6a; } .pagination>li>a:hover { color: #fff; background-color: #7d7d7d; border-color: #6a6a6a; } .pagination>.disabled>a, .pagination>.disabled>a:focus, .pagination>.disabled>a:hover, .pagination>.disabled>span, .pagination>.disabled>span:focus, .pagination>.disabled>span:hover { color: #eee; background-color: #2e2e2e; border-color: #6a6a6a; } .pagination.dark>li>a, .pagination.dark>li>span { color: #aaa; } /*--------------- settings ---------------*/ .section .form-horizontal .form-group .btn-default { font-size: 16px; border-color: #6d6d6d; background-color: #333; color: #FFF; } .section .form-horizontal .form-group .btn-default:hover, .section .form-horizontal .form-group .btn-default:focus { background-color: #737373; color: #FFF; } .section .form-horizontal .form-control:focus { border-color: #bbb; } /*--------------- share view ---------------*/ #notificationLabel, .ui-infobar .btn.ui-edit { color: #eee; border-color: #6a6a6a; } .ui-infobar__user-info li { color: #bbb; } footer { background: #101010; color: #bbb; border-top: 1px solid #454545; } footer a { color: #bbb; } /*--------------- doc view ---------------*/ .markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6, .markdown-body hr, #doc>h1 { color: #ddd; border-color: #777 !important; } .h1 .small, .h1 small, .h2 .small, .h2 small, .h3 .small, .h3 small, .h4 .small, .h4 small, .h5 .small, .h5 small, .h6 .small, .h6 small, h1 .small, h1 small, h2 .small, h2 small, h3 .small, h3 small, h4 .small, h4 small, h5 .small, h5 small, h6 .small, h6 small { color: #ddd; } .markdown-body p { color: #ddd; } .markdown-body a { color: #7bf; } .markdown-body a { color: #7bf !important; } .markdown-body ul li, .markdown-body ol li { color: #ddd; } .markdown-body blockquote { color: #ddd; border-left-color: #777; font-size: 16px; } .markdown-body code, code { color: #dfdfdf !important; background-color: #424a55; } .markdown-body pre { background-color: #1e1e1e; border: 1px solid #555 !important; color: #dfdfdf; } blockquote .small, blockquote footer, blockquote small { color: #bbb; } .mark, mark { background-color: rgba(255, 255, 0, 0.32) !important; color: #ddd; margin: .1em; padding: .1em .2em; } /* Todo list */ .task-list-item-checkbox { margin: 0.18em 0 0.2em -1.3em !important; } .task-list-item input[type=checkbox] { -webkit-appearance: none; -moz-appearance: none; appearance: none; position: relative; top: -1px; margin: 0 1rem 0 0; cursor: pointer; } .task-list-item input[type=checkbox]::before { -webkit-transition: all 0.1s ease-in-out; -moz-transition: all 0.1s ease-in-out; transition: all 0.1s ease-in-out; content: ""; position: absolute; left: 0; z-index: 1; width: 16px; height: 16px; border: 2px solid #F44336; } .task-list-item input[type=checkbox]:checked::before { -webkit-transform: rotate(-48deg); -moz-transform: rotate(-48deg); -ms-transform: rotate(-48deg); -o-transform: rotate(-48deg); transform: rotate(-48deg); height: 9px; border-color: #00E676; border-top-style: none; border-right-style: none; } .task-list-item input[type=checkbox]::after { content: ""; position: absolute; top: -0.125rem; left: 0; width: 16px; height: 16px; background: #333; cursor: pointer; } /* table */ .markdown-body table tr { background-color: #1e1e1e; border-top: none; border-bottom: 1px solid rgba(255, 255, 255, 0.3); } .markdown-body table tr:first-child { border-top: 1px solid rgba(255, 255, 255, 0.2); } .markdown-body table tr:nth-child(2n) { background-color: #333; } .markdown-body table tr th { color: #64B5F6; } .markdown-body table th, .markdown-body table td { border: none; } .markdown-body table tr th:first-child, .markdown-body table tr td:first-child { border-left: 1px solid rgba(255, 255, 255, 0.1); } .markdown-body table tr th:last-child, .markdown-body table tr td:last-child { border-right: 1px solid rgba(255, 255, 255, 0.1); } .markdown-body table tr td { color: #ddd; } .markdown-body pre.flow-chart, .markdown-body pre.sequence-diagram, .markdown-body pre.graphviz, .markdown-body pre.mermaid, .markdown-body pre.abc { background-color: #fff !important; } /* alert */ .alert h1, .alert h2, .alert h3, .alert h4, .alert h5, .alert h6, .alert p, .alert ul li, .alert ol li { color: #31708f; } .alert a { color: #002752; font-weight: 700; } .alert h1:first-child, .alert h2:first-child, .alert h3:first-child, .alert h4:first-child, .alert h5:first-child, .alert h6:first-child { margin-top: 0; } .markdown-body .alert>p { margin-top: 0px; margin-bottom: 10px; } .markdown-body .alert>ul, .markdown-body .alert>ol { margin-bottom: 16px; } .markdown-body .alert>*:last-child { margin-bottom: 0; } .alert-warning { background-color: #fff3cd; border-color: #ffeeba; } /* scroll bar */ .ui-edit-area .ui-resizable-handle.ui-resizable-e { background-color: #303030; border: 1px solid #303030; box-shadow: none; } /* info bar */ .ui-infobar { color: #999; } /* permission */ .permission-popover-btn-group .btn.focus, .permission-popover-btn-group .btn:active, .permission-popover-btn-group .btn:focus, .permission-popover-btn-group .btn.active { background-color: #6a6a6a !important; color: #eee !important; border-color: #555 !important; } .permission-popover-btn-group .btn:hover, .permission-popover-btn-group .btn.active:hover { background-color: #7d7d7d !important; color: #eee !important; border-color: #636363 !important; } .ui-delete-note a:hover, .ui-delete-note a:focus, .ui-delete-note a:active { background-color: #dc3545 !important; } .ui-invitee-invite { border-color: #6a6a6a !important; } .ui-invitee-invite:hover, .ui-invitee-invite:focus { background-color: #737373; color: #eee !important; } .ui-invitee.ui-invitee-list .ui-invitee-remove, .ui-invitee.ui-invitee-list .ui-invitee-remove:hover, .ui-invitee.ui-invitee-list .ui-invitee-remove:focus, .ui-invitee.ui-invitee-list .ui-invitee-remove:active { background-color: #dc3545; border: 1px solid #dc3545; } .select2-container { background: #202020; } .select2-container-multi .select2-choices .select2-search-field input { color: #eee; } .select2-container-multi .select2-choices .select2-search-field input.select2-active { color: #000; } .select2-drop { background: #202020; color: #eee; } .select2-results .select2-no-results, .select2-results .select2-searching, .select2-results .select2-ajax-error, .select2-results .select2-selection-limit { background: #202020; } /* table of contents block*/ .ui-toc-dropdown { width: 42vw; max-height: 90vh; overflow: auto; text-align: inherit; } /* table of contents text*/ .ui-toc-dropdown .nav>li>a { font-size: 14px; font-weight: bold; color: #ddd; } /* table of contents text: active*/ .ui-toc-dropdown .nav>.active:focus>a, .ui-toc-dropdown .nav>.active:hover>a, .ui-toc-dropdown .nav>.active>a { color: #7bf; border-left-color: #7bf; } /* table of contents text: focus, hover*/ .ui-toc-dropdown .nav>li>a:focus, .ui-toc-dropdown .nav>li>a:hover { color: #7bf; border-left-color: #7bf; } /* drop down floating table of contents */ .ui-toc-dropdown.dropdown-menu { background: #333; } .toc-menu a { color: #ddd; } .toc-menu a:focus, .toc-menu a:hover { color: #7bf; } /*--------------- editor ---------------*/ .cm-m-markdown { color: #ddd; } .cm-s-one-dark .cm-header, .cm-m-xml.cm-attribute { color: #ffa653; } .cm-s-one-dark .cm-string, .cm-s-one-dark .cm-variable-2 { color: #7bf; } .cm-m-markdown.cm-variable-3 { color: #ff7e7e; } .cm-s-one-dark .cm-link { color: #b0ee83; } .cm-s-one-dark .CodeMirror-linenumber { color: #666; } .cm-strong { color: #f4511e; } .cm-s-one-dark .cm-comment { color: #a9a9a9; } .cm-matchhighlight { color: #ffea00; } .cm-positive { color: #11bf64; } .cm-negative { color: #ff3e3e; } .dropdown-menu.CodeMirror-other-cursor { border: 2px solid #4d4d4d; background-color: #202020; } .dropdown-menu.CodeMirror-other-cursor li a { color: #ececec; } /*--------------- book mode ---------------*/ .topbar { background: #1e1e1e; } .btn.focus, .btn:focus, .btn:hover { color: #aaa; } .summary { background: #1e1e1e; } .summary, .toolbar { background: #1e1e1e !important; border-color: #4d4d4d !important; } .toolbar i { color: #fff; } .summary h1, .summary h2, .summary h3 .summary hr { color: #ddd; border-color: #777 !important; } .summary .nav>li>a { color: #7bf; } .summary .nav-pills>li.active>a, .summary .nav-pills>li.active>a:focus, .summary .nav-pills>li.active>a:hover { color: #ff9100; } .ui-summary-search { font-size: 16px; border: 1px solid #6D6D6D; background-color: #333; color: #FFF; } .summary h1, .summary h2, .summary h3, .summary h4, .summary h5, .summary h6 { border-color: #454545; } /* fix body background color to dark */ div[class$=container-mask] { background: #1e1e1e; z-index: 1; display: block; } /* notification */ .dropdown.ui-notification .ui-notification-label, .dropdown.ui-invitee .ui-invitee-label { color: #eee; border-color: #6a6a6a; } .ui-notification .dropdown-menu { border-top: 1px solid #555; } /*--------------- help ---------------*/ .modal-header { background-color: #2a2a2a; } .panel-default { border-color: #6d6d6d; } .panel-default>.panel-heading { background-color: #2a2a2a; color: #eee; border-color: #6d6d6d; } .panel-body { background: #2e2e2e; } .panel-body a { color: #7bf; } .table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th, .table>thead>tr>td, .table>thead>tr>th { border-color: #6d6d6d; } /*--------------- comment ---------------*/ .ui-comment-container .ui-comment-header { background-color: #2a2a2a; color: #eee; border-color: #6d6d6d; } .ui-comment-container { background-color: #2e2e2e; border-color: #6d6d6d; } .ui-comment-container .ui-comments-container .ui-comment .comment-author { color: #eee; } .ui-comment-container .ui-comments-container .ui-comment .timestamp { color: #aaa; } .ui-comment-container .ui-comments-container .ui-comment .comment-content { color: #eee; } .ui-comment-container .ui-comments-container .ui-comment .comment-menu { color: #eee; } .ui-comment-container .ui-comments-container .ui-comment .comment-menu .comment-dropdown-menu { background: #222; color: #eee; border-color: #555; } .ui-comment-container .ui-comments-container .ui-comment .comment-menu .comment-dropdown-menu>div:hover { background-color: #555555; color: #eee; } .ui-comment-container .ui-comments-container .ui-comment .comment-menu:hover, .ui-comment-container .ui-comments-container .ui-comment .comment-menu:active, .ui-comment-container .ui-comments-container .ui-comment .comment-menu.active { background-color: #737373; color: #eee; } .ui-comment-container .ui-comment-input-container { background-color: #3c3c3c; } .ui-comment-container textarea { background-color: #3e4045; color: #eee; border: 1px solid #6d6d6d; } .ui-comment-container textarea::placeholder, .ui-comment-container textarea::-webkit-input-placeholder, .ui-comment-container textarea:-moz-placeholder, .ui-comment-container textarea::-moz-placeholder, .ui-comment-container textarea:-ms-input-placeholder { color: #eee; } @keyframes highlight { 0% { background-color: #3c3c3c; } 30% { background-color: #3c3c3c; } 100% { background-color: transparent; } } /*--------------- template ---------------*/ .template-content .modal-header { background: #2a2a2a; } .template-content .close { color: #fff; } .template-content .modal-title { color: #eee; } .template-content .ui-templates-container { border-color: #6d6d6d; } .ui-templates-container .ui-create-template-btn { background: #446fab; color: #fff; } .ui-template-list-filter .ui-template-list-filter-label, .ui-template-list-filter .ui-template-list-filter-label:hover { color: #eee; } .ui-template-list .list-group-item.active { background: #4d4d4d; } .ui-template-list .list-group-item.active:focus { background: #4d4d4d !important; } .list-group-item.active, .list-group-item.active:focus, .list-group-item.active:hover { color: #eee; } .ui-template-list .list-group-item .list-group-item-heading { color: #eee; } .ui-template-list .list-group-item.active .list-group-item-heading { color: #eee; } .ui-template-list .list-group-item:hover { background: #4d4d4d !important; } .ui-template-item-menu { color: #eee !important; } .ui-template-list .list-group-item { color: #fff; } .ui-template-list .list-group-item .dropdown-container.open { background-color: #2a2a2a; } .ui-template-list .list-group-item .dropdown-container:hover { background-color: #2a2a2a !important; } .template-menu .more-template { border-color: #6d6d6d; } .template-menu .more-template:hover { color: #eee; border-color: #6d6d6d; } /*--------------- code mirror ---------------*/ .modal-content { background: #1f2226; } .modal-header { border-bottom: 1px solid #46484f; } .modal-footer { border-top: 1px solid #46484f; } a.list-group-item { background: #1f2226; color: #ddd; border: 1px solid #46484f; } a.list-group-item .list-group-item-heading { color: #ddd; } a.list-group-item:focus, a.list-group-item:hover { background: #434651; color: #ddd; } button.close { color: #ddd; opacity: .5; } .close:focus, .close:hover { color: #fff; opacity: .8; } .CodeMirror { background: #1f2226; } .CodeMirror-gutters { background: #1f2226; border-right: 1px solid rgba(204, 217, 255, 0.1); } .cm-s-default .cm-comment { color: #888; } .cm-s-default .cm-quote { color: #ddd; } .cm-s-default .cm-header { color: #ffa653; } .cm-s-default .cm-link { color: #b0ee83; } .cm-s-default .cm-string, .cm-s-default .cm-variable-2 { color: #7bf; } .cm-s-default .cm-def { color: #c678dd; } .cm-s-default .cm-number, .cm-s-default .cm-attribute, .cm-s-default .cm-qualifier, .cm-s-default .cm-plus, .cm-s-default .cm-atom { color: #eda35e; } .cm-s-default .cm-property, .cm-s-default .cm-variable, .cm-s-default .cm-variable-3, .cm-s-default .cm-operator, .cm-s-default .cm-bracket { color: #f76e79; } .cm-s-default .cm-keyword, .cm-s-default .cm-builtin, .cm-s-default .cm-tag { color: #98c379; } .modal-title { color: #ccc; } .modal-body { color: #ccc !important; } div[contenteditable]:empty:not(:focus):before { color: #aaa; } .CodeMirror pre { color: #ddd; } .CodeMirror pre span[style^="background-color: rgb(221, 251, 230)"] { background-color: #288c27 !important; } .CodeMirror pre span[style^="background-color: rgb(249, 215, 220)"] { background-color: #a52721 !important; } /*------- code highlight: Visual Stutdio Code theme for highlight.js -------*/ .hljs { background: #1E1E1E; color: #DCDCDC; } .hljs-keyword, .hljs-literal, .hljs-symbol, .hljs-name { color: #569CD6; } .hljs-link { color: #569CD6; text-decoration: underline; } .hljs-built_in, .hljs-type { color: #4EC9B0; } .hljs-number, .hljs-class { color: #B8D7A3; } .hljs-string, .hljs-meta-string { color: #D69D85; } .hljs-regexp, .hljs-template-tag { color: #d16969; } .hljs-title { color: #dcdcaa; } .hljs-subst, .hljs-function, .hljs-formula { color: #DCDCDC; } .hljs-comment, .hljs-quote { color: #57A64A; } .hljs-doctag { color: #608B4E; } .hljs-meta, .hljs-meta-keyword, .hljs-tag { color: #9B9B9B; } .hljs-variable, .hljs-template-variable { color: #BD63C5; } .hljs-params, .hljs-attr, .hljs-attribute, .hljs-builtin-name { color: #9CDCFE; } .hljs-section { color: gold; } .hljs-emphasis { font-style: italic; } .hljs-strong { font-weight: bold; } /* .hljs-code { font-family:'Monospace'; } */ .hljs-bullet, .hljs-selector-tag, .hljs-selector-id, .hljs-selector-class, .hljs-selector-attr, .hljs-selector-pseudo { color: #D7BA7D; } .hljs-addition { background-color: #155a36; color: #dfdfdf; display: inline-block; width: 100%; } .hljs-deletion { background-color: #872e2e; color: #dfdfdf; display: inline-block; width: 100%; } /*---------- code highlight: Visual Stutdio Code theme for Prism.js ----------*/ code[class*="language-"], pre[class*="language-"] { color: #DCDCDC; } :not(pre)>code[class*="language-"], pre[class*="language-"] { background: #1E1E1E; } .token.comment, .token.block-comment, .token.prolog, .token.cdata { color: #57A64A; } .token.doctype, .token.punctuation { color: #9B9B9B; } .token.tag, .token.entity { color: #569CD6; } .token.attr-name, .token.namespace, .token.deleted, .token.property, .token.builtin { color: #9CDCFE; } .token.function, .token.function-name { color: #dcdcaa; } .token.boolean, .token.keyword, .token.important { color: #569CD6; } .token.number { color: #B8D7A3; } .token.class-name, .token.constant { color: #4EC9B0; } .token.symbol { color: #f8c555; } .token.rule { color: #c586c0; } .token.selector { color: #D7BA7D; } .token.atrule { color: #cc99cd; } .token.string, .token.attr-value { color: #D69D85; } .token.char { color: #7ec699; } .token.variable { color: #BD63C5; } .token.regex { color: #d16969; } .token.operator { color: #DCDCDC; background: transparent; } .token.url { color: #67cdcc; } .token.important, .token.bold { font-weight: bold; } .token.italic { font-style: italic; } .token.entity { cursor: help; } .token.inserted { color: green; } /*---------- code highlight: dark theme for Gist ----------*/ .gist .gist-file { border: 1px solid #555; } .gist .gist-data { background-color: #1e1e1e; border-bottom: 1px solid #555; } .gist .gist-meta { background-color: #424a55; color: #eee; } .gist .gist-meta a { color: #eee; } .gist .highlight { color: #eee; background-color: #1e1e1e; } .gist .blob-num { color: #afafaf; } .gist .blob-code-inner { color: #dfdfdf; } .pl-mb { color: #fff !important; } .pl-c { color: #57A64A !important; } /* comment */ .pl-ent { color: #569CD6 !important; } /* entity */ .pl-e { color: #9CDCFE !important; } .pl-en { color: #4EC9B0 !important; } /* entity attribute */ .pl-smi { color: #9CDCFE !important; } .pl-k { color: #569cd6 !important; } .pl-c1, .pl-s .pl-v { color: #4EC9B0 !important; } .pl-pds, .pl-s, .pl-s .pl-pse .pl-s1, .pl-sr, .pl-sr .pl-cce, .pl-sr .pl-sra, .pl-sr .pl-sre, .pl-s .pl-s1 { color: #D69D85 !important; } .pl-s .pl-s1 .pl-pse { color: #c5dbff !important; } /* strings */ .diff-table .pl-c, .diff-table .pl-ent, .diff-table .pl-e, .diff-table .pl-en, .diff-table .pl-pds, .diff-table .pl-s, .diff-table .pl-s .pl-s1, .diff-table .pl-s .pl-pse .pl-s1, .diff-table .pl-sr, .diff-table .pl-sr .pl-cce, .diff-table .pl-sr .pl-sra, .diff-table .pl-sr .pl-sre, .diff-table .pl-k, .diff-table .pl-smi, .diff-table .pl-c1, .diff-table .pl-v { color: #eee !important; } </style>