改用 JScript 設計 .NET Framework 程式
.NET Framework 裡面有 jsc.exe,能編譯 JScript 程式,這表示可以用 JScript 寫 .NET Framework 程式:
若覺得物件導向程式語言的 C# 寫起來太囉嗦,純粹只想受用 .NET Framework 程式庫的功能,改用表述語言的 JScript 會有不錯的體驗~
學習這個語言,可下載《JScript 8.0 中文手册 chm 版》,下載頁面有「解压密码」,別忘了複製起來!
字元編碼
jsc.exe 在預設情況下,只能編譯符合 ASCII 的字元編碼,因此原始碼裡面有中文的話,必須以 Big5 字元編碼儲存,使用 UTF-8 或其它字元編碼的話,編譯時會有問題。
若想使用 UTF-8 字元編碼,必須下參數:
/codepage:65001
資料型態
畢竟 .NET Framework 是強型態的,所以寫 JScript 程式難免會遇到資料型態的問題。
JScript 可以在宣告變數時,使用 :
符號來指定資料型態,例如:
var a : String[] = ["AAA", "BBB", "CCC"];
這語法也能用在函式的傳回值型態。
類別、介面、套件
用 JScript 也是可以寫類別來用的:
class 類別名稱 extends 父類別{
var 屬性 : 資料型態 = 初始值;
function 方法() : 傳回型態{
}
function 類別名稱(){
}
}
前面也能冠上 public
或 private
限制存取權限。
也支援介面:
interface 介面名稱{
function 方法();
}
class 類別名稱 implements 介面名稱{
function 方法(){
}
}
還有套件:
package 命名空間{
class 類別名稱{
}
}
new 命名空間.類別名稱();
import 命名空間;
new 類別名稱();
泛型
JScript .NET 不支援泛型語法,因此無法正常操作像是 System.Collections.Generic 的類別。
真的要用泛型的類別,只能先用 C# 重新包裝成不用泛型的類別,再編譯成 *.dll 給 JScript .NET 使用。
Windows Forms 的事件處理
若 C# 的事件寫法為:
那麼在 JScript 就改為:
error JS1259: 被參考的組件相依於另一個未被參考或找不到的組件
加入 import Accessibility
這行程式即可解決問題!
error JS1183: 一個以上的方法或屬性符合此引數清單
這問題的解決辦法,就是不要把程式碼直接寫在全域範疇跑,看是要寫在 (function(){})()
裡面,或者寫在 function xxx(){}
裡面再呼叫 xxx() 執行程式。
這是因為 ECMAScript 的全域範疇,其實是最頂級物件的區域範疇。在網頁瀏覽器的 JavaScript 就是 window 物件,在 .NET 的 JScript 則是 Object 物件。直接把程式碼寫在全域,變數和函式往往變成 Object 的成員,而不是獨立的領域範疇。只有把程式寫在函式裡面,才不會汙染區域範疇。
error JS1112: 必須是類型名稱
這問題發生在物件的成員和指定的類別名稱相同:
class Form1 extends Form{
function Form1(){
this.Size = new Size(640, 480);
}
}
這跟 ECMAScript 的作用域有關,在 this 也有 Size 的情況下,編譯器認為 new 的 Size 是指 this 的 Size,而不是 import 進來的 Size。1
所以解決辦法就是 new 後面的類別用完整命名空間:
this.Size = new System.Drawing.Size(640, 440);
這問題在多型機制下也會發生,像是:
this.ClientSize = new Size(640, 440);
這是 ECMAScript 特性上的問題,所以寫 JScript .NET 經常會發生這種事,規避不了。請習以為常,看到編譯器拋出這訊息,隨即補上完整命名空間就好,不用為此感到焦躁或挫折。
如果就是很反感,那一律用完整命名空間寫程式吧!這樣寫 JScript .NET 程式的人非常非常多,你不會是少數派 :)
其實 .NET Framework 的屬性和方法別用大寫開頭,而是小寫開頭,就不會有這鳥事了!
print()
.NET 的 JScript 可以用 print()
來輸出,取代落落長的 Console.WriteLine(),這樣一來也不用 import System 了。
new
new 後面的類別,不需要參數的話,可以省略 () 符號,例如 var button = new Button;
或 Application.Run(new Form);
。
雖然這不是 JScript 才有的特性,ECMAScript 就是這樣定義。
More Effective C#
處理資料型別
使用屬性取代可存取的資料成員
可變動的資料優先使用隱藏屬性
實值型別優先使其具不可變性
區分實值與參考型別
確保 0 是實值型別的有效狀態
確保屬性運作如資料一般
使用 Tuples 限制型別的範圍
在匿名型別上定義區域函式
了解多種相等概念之間的關係
了解 GetHashCode() 的陷阱
API 設計
在你的 API 中避免轉換運算子
使用選擇性引數減少方法的多載
限制型別的可見性
優先定義並實作介面進行繼承
了解介面與 Virtual Method 之間差異
為通知實作事件模式
避免傳回內部類別物件的參考
優先使用 Override 替代 Event Handler
避免在基底類別中定義方法多載
了解事件如何增進物件之間執行期的耦合
只宣告 Nonvirtual Event
建立清楚的、最少的,以及完整的方法群
部分類別的建構函式、更動子與 Event handler 使用部分方法
避免使用 ICloneable,因為它限制你的設計選擇
Array 引數限制只使用 params 陣列
在 Iterators 與 Async 方法中使用區域函式啟動立即錯誤回報
以 Task 為基礎的非同步程式設計
非同步工作使用 Async 方法
永遠不要寫 async void 方法
避免結合同步與非同步方法
避免執行緒配置及 Context Switchesv
避免非必要的封送處理(Marshalling)Contextv
使用 Task 物件合成非同步工作
考慮實作 Task 取消協定(Task Cancellation Protocol)
緩衝擴充的非同步回傳值
平行處理
學習 PLINQ 如何實作平行演算法
建構有考慮例外情況的平行演算法
使用執行緒區集取代建立執行緒
使用 BackgroundWorker 做跨執行緒通訊
了解 XAML 環境中的跨執行緒呼叫
使用 lock() 作為同步處理的首選
鎖定 Handles 使用最小可能的範圍
避免在鎖定的區段呼叫不明的程式碼
動態程式設計
了解動態程式設計的利弊
透過動態型別運用泛型引數執行期的型別
Data-Driven 動態型別使用 DynamicObject 或 IDynamicMetaObjectProvider
了解如何運用 Expression API
在公開的 API 中減少動態物件的使用
參與全球 C# 社群
尋求最好的答案,而不是最受歡迎的答案
參與規格及程式碼的訂定
考慮用分析器自動化慣用法
LINQ 查詢語句、LINQ API、Collections API 的使用時機
對於查詢語句、LINQ API、集合的使用時機,我有自己的一套用法,雖然我的做法不一定對,但還是提供給各位斟酌看看,或許值得參考~
LINQ 查詢語句
我不把查詢語句當 LINQ,而是當運算式來用,所以一定會把結果指派給變數:
如果沒有要把結果指派給變數,我不會使用查詢語句,會改用 LINQ API 或 Collections API 甚至 foreach 迴圈。
LINQ API
當我想在一句程式碼就批次處理好資料,用 LINQ API:
我不會在使用 LINQ API 時將結果傳回給變數,它就是函數式風格的程式設計,用完即丟,資料不用保存下來。
Collections API
操作的是要保存下來的資料,自然就是用集合一行一行讀寫和操作了:
我會盡量使用集合,展現物件導向程式設計的可讀性!查詢語句和 LINQ API 是那種寫起來很爽,讀起來很幹的程式碼,修改起來沒有物件導向的程式碼方便、穩妥。