Posts
C# Static Field 陷阱:在建構子中指派 this
這個專案示範了一個常見但危險的模式:在實例建構子(Instance Constructor)中將 this 指派給靜態欄位(Static Field)。這通常是為了方便全域存取「當前」物件,但往往會導致意想不到的錯誤。
核心問題 在 Person 類別中,我們看到這樣的程式碼:
public class Person { // 靜態欄位,所有實例共享同一個變數 public static Person CurrentPerson; public string Name; public Person(string name, int age) { Name = name; // ... CurrentPerson = this; // 每次 new 一個新物件,都會覆蓋這個靜態欄位! } } 發生了什麼事? 當你建立 Person A 時,CurrentPerson 指向 A。 當你建立 Person B 時,建構子再次執行,CurrentPerson 被更新指向 B。A 的全域參考就此遺失。 當你建立 Person C 時,CurrentPerson 再次被更新指向 C。 這意味著 Person.CurrentPerson 永遠只指向最後被建立的那個物件。如果你的系統依賴這個靜態屬性來存取「主要使用者」或「設定檔」,一旦程式的其他部分無意間建立了一個新的 Person 物件(例如暫時性的變數),原本的全域狀態就會被悄悄替換掉。
程式碼行為分析 執行 Program.cs 的輸出結果清楚地展示了這個現象:
Posts
C# volatile 詳解:理解多執行緒可見性 (Memory Visibility)
當我們編寫多執行緒程式時,最容易被忽視的概念之一就是記憶體可見性 (Memory Visibility)。這個範例專案演示了在沒有適當同步機制的情況下,一個執行緒對變數的修改如何可能被另一個執行緒「視而不見」,以及 volatile 關鍵字如何解決這個問題。
核心問題:緩存與優化 現代 CPU 和編譯器為了效能,會做很多優化:
CPU 快取 (L1/L2 Cache):CPU 核心可能會將變數的值暫存在自己的快取中,而不是每次都去讀寫較慢的主記憶體 (RAM)。 指令重排 (Instruction Reordering):CPU 或編譯器可能會改變指令的執行順序以優化管線 (Pipeline)。 暫存器分配 (Register Allocation):編譯器 (JIT) 可能將變數直接存在 CPU 暫存器中,完全不寫回記憶體。 情境 A:沒有使用 volatile 在 WithoutVolatileDemo 類別中:
private bool _running = true; // 普通欄位 // Worker Thread while (_running) { /* ... */ } // Main Thread _running = false; 發生了什麼事?
Release 模式下,JIT 編譯器看到 while (_running) 迴圈內部沒有任何程式碼修改 _running。 它可能會將 _running 的值讀入 CPU 暫存器,並認為「這個值永遠不會變」。 於是迴圈變成了 while (true) 的死路。 即使主執行緒將記憶體中的 _running 改為 false,Worker 執行緒仍然在看它暫存器裡的舊值 (true)。 這就是可見性問題:主執行緒的寫入對 Worker 執行緒不可見。
Posts
Speck-Kit:用 AI 驅動的規格化開發工作流
Speck-Kit 是一套規格化的專案管理框架,專為 AI 輔助軟體開發設計。它透過結構化的規格模板、分階段的開發流程,以及與 GitHub Copilot 深度整合的自訂 Agent,讓團隊在動手寫程式之前就能完成完整的需求釐清與技術規劃。本文以我的圖書管理系統(Library)專案為例,介紹 Speck-Kit 的核心概念與實際應用。
1. 什麼是 Speck-Kit? Speck-Kit(目前版本 v0.3.2)是一個開發流程的「元框架」,它不產出程式碼,而是定義如何產出程式碼。核心理念是:
在實作之前,先把需求寫清楚。
它提供了以下能力:
結構化規格模板:以 User Story、Acceptance Criteria、Gherkin 測試情境定義功能需求 分階段開發流程:Clarify → Specify → Plan → Implement → Tasks Copilot 自訂 Agent:每個階段對應一個專屬 Agent,共 9 個 PowerShell 自動化腳本:環境檢查、功能建立、計畫初始化 專案 Constitution:定義不可違反的品質、測試、效能標準 2. 安裝 Spec-Kit 官方 GitHub:https://github.com/github/spec-kit 前置需求 作業系統:Linux / macOS / Windows Python 3.11+:https://www.python.org/downloads/ Git:https://git-scm.com/downloads uv(Python 套件管理工具):https://docs.astral.sh/uv/ 支援的 AI 編碼助手(如 GitHub Copilot、Claude Code、Cursor 等) 安裝 Specify CLI 方式一:永久安裝(推薦) 安裝一次,隨處可用:
uv tool install specify-cli --from git+https://github.
Posts
Oracle Database 23ai 入門指南
這是一份針對開發者的 Oracle Database 23ai 快速入門指南,內容涵蓋其核心新功能、安裝步驟,以及如何開始您的第一個查詢。本文結合了官方建議與實用的操作範例。
1. 核心新功能:不僅僅是資料庫 Oracle 23ai 的標語是 “AI for your Data”,它引入了多項突破性功能,旨在將 AI 和開發者便利性深度整合到資料庫中。
🚀 AI Vector Search 這可能是 23ai 最重大的新功能。它讓您能直接在 Oracle 資料庫中儲存、索引和搜尋向量(Vector)。
什麼是向量? 向量是物件(如文字、圖片、音訊)的數學表示。 能做什麼? 您可以進行 “語意搜尋” 或 “相似性搜尋”。例如,找到與一張圖片 “相似” 的所有圖片,或與一段文字描述 “語意相關” 的文件。這對於建立推薦系統、RAG (檢索增強生成) 應用至關重要。 🚀 JSON Relational Duality View 此功能完美地橋接了 JSON 文件的靈活性與關聯式模型的結構化優勢。
開發者視角:開發者可以繼續使用他們熟悉的 JSON 格式來存取和操作資料。 DBA 視角:資料庫內部將這些 JSON 文件對應到標準的關聯式表格。 優點:兼具兩者之長,開發快、查詢快、資料一致性高。 🚀 Operational Property Graphs (OPG) 您現在可以直接在 Oracle 資料庫上執行圖形資料分析。
能做什麼? 分析複雜的關係網路,如社交網路分析、金融詐欺偵測、供應鏈路徑規劃等。 🚀 True Cache 一個在資料庫中介層運作的高效能快取。它可以顯著提升應用程式的回應速度,且能自動保持與主資料庫的資料一致性,開發者無需手動管理快取失效。
2. 安裝指南 您可以選擇適合自己的安裝方式。對於初學者,我們推薦使用 Docker,因为它更簡單快速。
Posts
vue init webpack [專案名稱]
安裝 Vue CLI 安裝 npm install -g vue-cli 安裝 npm install -g @vue/cli- 2. 建立專案 vue init webpack staff 3. 設定vue router 4. 前端專案結構 參考 https://cli.vuejs.org/zh/guide/creating-a-project.html#%E6%8B%89%E5%8F%96-2-x-%E6%A8%A1%E6%9D%BF-%E6%97%A7%E7%89%88%E6%9C%AC
Posts
使用 Vue CLI 建立專案
安裝 Vue CLI 安裝 Vue CLI npm install -g @vue/cli 使用 vue create [專案名稱] 或 vue create . 選擇手動建立專案 (Manually select features) 套件選用 Babel、Vuex、CSS Pre-processors Vue版本,選擇2 Vue-Router為了讓在網址上會多出#,輸入n 選擇Sass/SCSS 存檔在 package.json 不要儲存相關設定 安裝完成 參考 https://hsuchihting.github.io/vue-js/20200404/497821688/
Posts
VSCode 擴充套件設定
Prettier - Code formatter Vue - Official { "prettier.useEditorConfig": false, "prettier.printWidth": 200, // 超過 XX 個字元就換行 "prettier.tabWidth": 2, // 程式碼縮排 2 個空格 "prettier.useTabs": false, // 不使用 tab,預設使用空格 "prettier.semi": true, // 語句結尾加上分號 "prettier.singleQuote": false, // 使用單引號,預設使用雙引號 "prettier.quoteProps": "as-needed", // 預設 'as-needed',只有在屬性名稱包含特殊字元或空格時才會使用雙引號。否則,它將使用單引號。 "prettier.trailingComma": "es5", // 在物件或陣列最後一個元素後面加上逗號 "prettier.bracketSpacing": true, // 在物件的左右括號間加上空格 "prettier.arrowParens": "always", // 箭頭函式只有一個參數時,也需要括號 "prettier.endOfLine": "lf", // 換行符號,預設 lf "prettier.proseWrap": "preserve", // 是否要换行 "prettier.bracketSameLine": true, //結束標籤>不換行 "prettier.htmlWhitespaceSensitivity": "ignore", //ignore的話就是所有元素間的空格都會被忽略 "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.
Posts
父組件傳遞資料在子組件偵測應用
(CustomSelect.vue)子組件要偵聽父組件(App.vue)來的props,使用watch監聽,來變更子組件的數據。(備註:computed也可以)
父組件 App.vue <template> <div id="app"> 父組件: <el-input-number v-model="parentSelectedValue" @change="handleChange" :min="1" :max="10" label="描述文字"></el-input-number> <custom-select :parentSelectedValue="parentSelectedValue" :title="title" @returnSelectedChange="getSelectedValue"></custom-select> 子組件,變更時選擇的數值:{{ selectedValue }} </div> </template> <script> import customSelect from "./components/CustomSelect.vue"; export default { name: "App", components: { customSelect, }, data() { return { selectedValue: null, title: "縣市", parentSelectedValue: null, }; }, methods: { getSelectedValue(val) { this.selectedValue = val; }, handleChange(value) { this.parentSelectedValue = value; }, }, }; </script> <style></style> 子組件 CustomSelect.vue <template> <div> <b>{{ title }}:</b> <el-select v-model="value" placeholder="請選擇縣市" @change="selectedChange"> <el-option v-for="item in options" :key="item.
Posts
建立 Vue.js 前端專案
安裝 Node.js 安裝 Vue CLI npm install -g @vue/cli 創建 Vue.js 專案 vue create my-project 啟動 Vue.js 專案 cd my-project npm run serve
Posts
Vue Provide 和 Inject
原本要傳遞三層
App -> FirstLayer -> SecondLayer -> ThirdLayer
可使用Provide和Inject提供跨多層組件傳遞數據的方式
App -> ThirdLayer
App.vue <template> <div id="app"> <div :class="theme"> <button @click="changeFontSize">"第一層"字型變大</button> <FirstLayer ref="first" /> </div> </div> </template> <script> import FirstLayer from "./components/FirstLayer"; export default { name: "App", data() { return { myName: "ming", theme: "theme" }; }, provide() { return { myName: this.myName, changeBgColor: this.changeBgColor }; }, components: { FirstLayer }, methods: { changeBgColor() { console.log("changeBgColor"); this.theme = "dark-theme"; }, changeFontSize() { this.