忘了就查。搜尋框打關鍵字即時過濾(中英都可),程式碼右上角可一鍵複製。
沒有符合的項目,換個關鍵字試試。
你筆記裡的弱點——用就熟,不是背
var list = new List<int>(); list.Add(5); // 加 list.Remove(5); // 移除值 list.RemoveAt(0); // 移除索引 int n = list.Count; // 數量(不是 Length) bool has = list.Contains(5); foreach (var x in list) { }
var map = new Dictionary<string,int>(); map["a"] = 1; // 加 / 改 if (map.ContainsKey("a")) { } // 先查再用 if (map.TryGetValue("a", out var v)) { } // 更安全 map.Remove("a"); foreach (var kv in map) { var k=kv.Key; var val=kv.Value; }
ContainsKey 再存,一輪 O(n) 用空間換時間。var set = new HashSet<int>(); set.Add(1); // 重複加不會錯,回傳 false bool has = set.Contains(1); // O(1) 查存在 set.Remove(1);
var st = new Stack<int>(); // 後進先出 st.Push(1); int top = st.Pop(); int peek = st.Peek(); var q = new Queue<int>(); // 先進先出 q.Enqueue(1); int first = q.Dequeue(); int pk = q.Peek();
int[] arr = new int[5]; // 固定長度 5,預設 0 int[] arr2 = { 1, 2, 3 }; // 直接給值 int len = arr.Length; // 陣列用 Length(List 用 Count) int[,] grid = new int[3,3]; // 二維
null 處理、string、async/await
var name = user?.Name ?? "訪客"; // user 為 null → 整段不爆,回 "訪客" // ?. null 條件:是 null 就停,回 null // ?? null 合併:左邊 null 就取右邊 user?.DoSomething(); // null 就不呼叫,不報錯 list ??= new(); // 是 null 才指派
string s = "abc"; s = s + "d"; // 產生新字串,不是改原本 // 大量字串相接 → 用 StringBuilder var sb = new StringBuilder(); sb.Append("x"); string r = sb.ToString(); string msg = $"Hi {name}, {count} 筆"; // 字串插值
public async Task<User> GetAsync(int id) { var u = await _db.Users.FirstOrDefaultAsync(x => x.Id == id); return u; }
Task/Task<T>;await 等待但不阻塞 thread,等待期間 thread 還給 pool,server 可處理別的 request。不一定開新 thread。| 修飾詞 | 誰能存取 |
|---|---|
public | 任何地方 |
private | 只有這個 class 內 |
protected | 這個 class + 繼承它的子類別 |
internal | 同一個專案(組件)內 |
int/bool/double/struct = 傳值(複本,改了不影響外面);string/陣列/class/物件 = 傳參考(指向同一份)。5 秒說出「在做什麼、為什麼、有沒有限制」
list.Where(x => x.Age > 18) // 過濾(等於 SQL WHERE) .Select(x => x.Name) // 投影:只取需要的欄位 .OrderBy(x => x.Age) // 排序(降冪 OrderByDescending) .ToList(); list.FirstOrDefault(x => x.Id==1) // 第一個,沒有回 null(不報錯) list.Any(x => x.Active) // 有沒有符合的,回 bool(比 Count>0 快) list.Count(x => x.Active) // 數符合的 list.GroupBy(x => x.City) // 分組 list.Sum(x => x.Fee) // 加總
// Include = JOIN,把關聯資料一起撈,省第二次查詢 _db.Orders.Include(o => o.Details) // IQueryable 動態疊加:條件不固定時只發一次 SQL var q = _db.Users.AsQueryable(); if (active) q = q.Where(u => u.Active); var result = await q.ToListAsync();
.Where() 是 C# 在記憶體跑;IQueryable 上的會翻成 SQL 丟資料庫。JOIN 與 COUNT 陷阱——你連續卡過三次,必看
SELECT A.* FROM 顧客 A JOIN 關聯 C ON A.顧客ID = C.顧客ID JOIN 商店 B ON C.商店ID = B.商店ID WHERE B.商店名稱 = '某商店';
| JOIN | 意思 |
|---|---|
INNER JOIN | 兩邊都有才出現(預設) |
LEFT JOIN | 左表全保留,右表沒有補 NULL |
-- 找沒有員工的部門 SELECT d.name FROM departments d LEFT JOIN employees e ON d.id = e.dept_id WHERE e.id IS NULL;
COUNT(e.id),不要 COUNT(*) 或 COUNT(d.id)(會把沒員工的算成 1)。SELECT dept_id, COUNT(*) AS 人數, AVG(salary) AS 平均 FROM employees GROUP BY dept_id HAVING COUNT(*) > 3 -- 分組後過濾用 HAVING(不是 WHERE) ORDER BY 人數 DESC;
SUM/AVG/MAX/MIN 沒資料回 NULL,要 COALESCE(SUM(x),0)。INSERT INTO t (a,b) VALUES (1,2); UPDATE t SET a=1 WHERE id=5; -- 一定要 WHERE! DELETE FROM t WHERE id=5; -- 一定要 WHERE!
ROLLBACK,避免資料不一致。WHERE name LIKE '%王%' -- 模糊:% 任意, _ 單一 WHERE id IN (1,2,3) WHERE age BETWEEN 18 AND 30 SELECT TOP 10 * FROM t -- SQL Server 取前 N 筆 SELECT DISTINCT city FROM t -- 去重 CASE WHEN age>=18 THEN '成年' ELSE '未成年' END
舊版 ASP.NET 多用 ADO.NET 手寫——前兩週的重頭戲
<connectionStrings> <add name="DbConn" connectionString="Server=主機名;Database=資料庫名;User Id=帳號;Password=密碼;" providerName="System.Data.SqlClient" /> </connectionStrings> <!-- Windows 驗證版:Server=.;Database=DB;Integrated Security=True; -->
ConfigurationManager.ConnectionStrings["DbConn"].ConnectionString(需 using System.Configuration;)。密碼別寫死在程式碼。using System.Data.SqlClient; string cs = ConfigurationManager.ConnectionStrings["DbConn"].ConnectionString; using (var conn = new SqlConnection(cs)) { conn.Open(); string sql = "SELECT Id, Name FROM Users WHERE Age > @age"; using (var cmd = new SqlCommand(sql, conn)) { cmd.Parameters.AddWithValue("@age", 18); // 參數化! using (var rd = cmd.ExecuteReader()) { while (rd.Read()) { int id = (int)rd["Id"]; string name = rd["Name"].ToString(); } } } } // using 自動關連線,不會洩漏
ExecuteReader() 讀多筆 → ExecuteScalar() 取單一值(如 COUNT) → ExecuteNonQuery() 做 INSERT/UPDATE/DELETE(回傳影響筆數)。// ❌ 絕對不要字串相接(會被注入攻擊) string bad = "SELECT * FROM Users WHERE Name = '" + input + "'"; // ✅ 一律用參數 cmd.CommandText = "SELECT * FROM Users WHERE Name = @name"; cmd.Parameters.AddWithValue("@name", input);
string sql = "INSERT INTO Users(Name) VALUES(@n); SELECT SCOPE_IDENTITY();"; var cmd = new SqlCommand(sql, conn); cmd.Parameters.AddWithValue("@n", "小明"); int newId = Convert.ToInt32(cmd.ExecuteScalar()); // 拿剛插入的自增 ID
using (var tx = conn.BeginTransaction()) { try { var cmd = new SqlCommand(sql, conn, tx); // 帶入 tx cmd.ExecuteNonQuery(); tx.Commit(); // 全部成功才提交 } catch { tx.Rollback(); // 任一步失敗就全退回 throw; } }
CREATE TABLE Users ( Id INT IDENTITY(1,1) PRIMARY KEY, -- 自增主鍵 Name NVARCHAR(50) NOT NULL, -- 中文用 N 開頭 Email NVARCHAR(100) UNIQUE, Age INT DEFAULT 0, DeptId INT, CreatedAt DATETIME DEFAULT GETDATE(), FOREIGN KEY (DeptId) REFERENCES Departments(Id) -- 外鍵 );
| 型別 | 用途 |
|---|---|
INT / BIGINT | 整數 / 大整數 |
NVARCHAR(n) | 變動長字串(支援中文,n=最大長度) |
VARCHAR(n) | 變動長字串(僅英數) |
DECIMAL(18,2) | 精確小數(金額用,總18位、小數2位) |
BIT | 布林(0/1) |
DATETIME / DATE | 日期時間 / 只有日期 |
DECIMAL。存中文欄位用 NVARCHAR 不是 VARCHAR。ALTER TABLE Users ADD Phone NVARCHAR(20); -- 加欄位 ALTER TABLE Users DROP COLUMN Phone; -- 刪欄位 ALTER TABLE Users ALTER COLUMN Name NVARCHAR(100); -- 改型別 CREATE INDEX IX_Users_Name ON Users(Name); -- 建索引(查詢加速) DROP TABLE Users; -- 刪整張表(小心!)
DbContext + LINQ。語法 EF6 與 EF Core 大致相同,差異標註在下方。public class AppDbContext : DbContext { // EF6:建構式傳 Web.config 裡 connectionStrings 的 name public AppDbContext() : base("name=DbConn") { } public DbSet<User> Users { get; set; } public DbSet<Dept> Depts { get; set; } } // 用的時候 using 包起來,會自動關 using (var db = new AppDbContext()) { ... }
"name=DbConn" 對應 Web.config;EF Core 改在 OnConfiguring 或 DI 用 UseSqlServer(...)。using (var db = new AppDbContext()) { // 查 var u = db.Users.Find(1); // 用主鍵找 var u2 = db.Users.FirstOrDefault(x => x.Name=="小明"); var adults = db.Users.Where(x => x.Age >= 18).ToList(); // 增 db.Users.Add(new User { Name = "小華" }); // 改(先查出來、改屬性) u.Name = "新名字"; // 刪 db.Users.Remove(u2); db.SaveChanges(); // ★ 增改刪都要這行才真正寫進 DB }
SaveChanges() 才送一次到資料庫。漏掉就不會存。// Include = JOIN,把關聯資料一起撈(省第二次查詢) var list = db.Users .Include(u => u.Dept) // 連部門一起帶 .Where(u => u.Active) .Select(u => new { u.Name, Dept = u.Dept.Name }) // 只取需要欄位 .ToList(); // async 版(EF6 需 using System.Data.Entity;) var u = await db.Users.FirstOrDefaultAsync(x => x.Id == id); var all = await db.Users.ToListAsync(); await db.SaveChangesAsync();
| ADO.NET | EF | |
|---|---|---|
| SQL | 自己手寫 | LINQ 自動翻譯 |
| 掌控度 | 高、效能可調 | 方便、開發快 |
| 適合 | 複雜查詢、舊系統 | 一般 CRUD |
| 防注入 | 要自己參數化 | 預設參數化 |
舊版 .NET Framework,Controller / Razor 觀念同 Core
public class HomeController : Controller { public ActionResult Index() => View(); // 回畫面 public ActionResult List() => View(model); // 帶資料 public JsonResult Api() => Json(data, JsonRequestBehavior.AllowGet); public ActionResult Go() => RedirectToAction("Index"); [HttpPost] public ActionResult Save(Model m) { ... } // 表單自動綁到 m }
IActionResult + return Ok()/View();MVC 5 用 ActionResult。Json 在 5 要加 JsonRequestBehavior.AllowGet。@model MyApp.Models.User @* 宣告 model 型別 *@ <h1>@Model.Name</h1> @* 輸出變數 *@ @if (Model.Active) { <p>啟用</p> } @foreach (var x in Model.Items) { <li>@x.Name</li> } @Html.ActionLink("連結", "Index", "Home") @Html.TextBoxFor(m => m.Name) @* 綁 model 的輸入框 *@
| 項目 | MVC 5 | Core |
|---|---|---|
| 設定檔 | Web.config | appsettings.json |
| 啟動 | Global.asax | Program.cs |
| DI | Autofac/Unity | 內建 |
| 部署 | IIS | 跨平台/Docker |
你筆試踩過的——falsy 清單、const、this
// falsy: false, 0, "", null, undefined, NaN // 其他全 truthy!包括: if ([]) // truthy(空陣列) if ({}) // truthy(空物件) if ("0") // truthy(非空字串) if ("false") // truthy
const arr = [1,2,3]; arr.push(4); // ✅ 合法,改內容 OK arr = [5,6]; // ❌ 報錯,重新指派不行
1 + "2" // "12" (+ 遇字串→相接) "5" - 2 // 3 (- * / % →轉數字) 0 == "" // true (== 會隱式轉型) 0 === "" // false (=== 型別也要相同)
===,避免隱式轉型的坑。// var:函式作用域,提升並自動給 undefined // let/const:區塊作用域,提升但不初始化 → TDZ console.log(x); let x; // ❌ 報錯(宣告前用) let y; console.log(y); // ✅ undefined(宣告後用)
()=>{} 沒有自己的 this,用「定義時外層的 this」(語彙作用域);普通 function(){} 的 this 看「誰呼叫它」。callback 用箭頭才不會搞丟 this。undefined=宣告了沒賦值(系統給的);null=主動設成空(自己給的);完全沒宣告就用=ReferenceError。