目錄:
自己一直在 配置化編程 方面努力,希望 項目復雜的功能可以用 簡單的 配置來完成;
於是 在自己的網站中,使用了一個自己寫的 數據庫框架,為了給框架提速,於是就 想將 少於 5000 的數據表 進行全表緩存;
然后所有的 數據 就由框架 從緩存中 按照條件 檢索——相當於 內存檢索;
這時,問題就來了 —— 整個項目,Sql 腳本的 Where 條件,千變萬化;
如何判斷 某個對象 是否 符合 一個字符串的表達式,這就讓我 頭疼了;
於是經過搜索,得到: http://bbs.csdn.net/topics/230073145;
最終的解法 是 DataTable.Compute() 函數;還有一個 是 使用微軟動態編譯技術 的解決方案(這個才是真正無敵的方法)。
但是確有弊端:微軟 動態編譯技術 計算字符串表達式,即時計算 “1+1”,也需要 300ms,5000個數據的檢索,這個是我所無法容忍的。
於是就想 寫一個 字符串計算 的算法;
算法從去年5月完成,歷時 2周業余時間,完成第一版;
今年7月開始,參與了幾個 工作流項目的開發,覺着鬧心:工作流 應該和 功能分開,結果我看到,代碼中,業務代碼和工作流代碼 縱橫交錯;特別鬧心;
於是就想 抽象一個流程設計器:讓開發人員一心一意寫業務代碼,工作流的代碼 全部使用配置,即時修改了流程,開發人員也不用 修改任何代碼;
而 流程設計器 的的手稿過程中,發現 不可避免 的有一個環節:條件判斷——這個非得使用 字符串計算算法;
於是 改版 第一版算法代碼,得到今天的第二版 Laura.Compute;
新版本 算法,字符串表達式 兼容 SQL腳本(和SQL腳本類似的 字符串格式);
新版本 算法,支持 動態參數(就像 SQL中 WHERE FName=@FName 一樣);
新版本 支持 預分析,分析一次 多次執行(可用不同參數);
運算速度 達到 (分析+計算)*20000次 = 2000ms; 分析*1次+計算*20000次 = 150ms;
順手實現了 字符串表達式 的內存檢索(Word LIKE '%cat%'),50000單詞,內存檢索時間 800ms;
順手實現了 字符串表達式 的 內存排序(Word DESC, ID ASC),50000單詞,內存排序時間 2400ms;

使用代碼:
//分析一個 表達式,得到 表達式結構 對象
ExpressSchema expressSchema3 = ExpressSchema.Create("\"ShuXiaolong\" IN (\"ShuXiaolong\",\"ZhangSan\")"); //給定參數,計算這個 表達式結構 對象 在指定參數下 的運行結果
object value = expressSchema3.Compute(null); Console.WriteLine(value); 
        
計算結果:

其他用法:
以上只是 一個簡單的 表達式:判斷 某個 字符串 是否在 一個 數組中。
以下即為 其他 功能(這些功能 全都是 算法的 插件,任何開發人員都可以 在 任意程序集 中 擴展本算法):
 插件名稱: 關鍵字: 運算優先級: DateAddComputeMethod DATEADD    1000000 DateConvertComputeMethod CONVERTDATE 1000000 DateDiffComputeMethod DATEDIFF     1000000 DateFormatComputeMethod DATEFORMAT    1000000 DateNowComputeMethod GETDATE 1000000 DatePartComputeMethod DATEPART 1000000 GuidNewComputeMethod NEWID 1000000 StringLengthComputeMethod LEN 1000000 StringReplaceComputeMethod REPLACE 1000000 PowComputeSymbol ^                      100000 MultiplyComputeSymbol *                      10000 RemainComputeSymbol %                      10000 DivideComputeSymbol /                      10000 PlusComputeSymbol +                      1000 MinusComputeSymbol -                      1000 LikeEqualComputeSymbol LIKE 700 LessThanEqualComputeSymbol <=                     685 GreaterThanEqualComputeSymbol >=                     680 LessThanComputeSymbol <                      675 GreaterThanComputeSymbol >                      670 StrictEqualComputeSymbol ===                    610 EqualComputeSymbol ==                     605 BaseEqualComputeSymbol =                      600 AndComputeSymbol AND 525 AndSignComputeSymbol &&                     525 OrComputeSymbol OR 520 OrSignComputeSymbol ||                     520 TernaryComputeSymbol ?:                     100 InComputeMethod IN 未定(默認為 0) 
        
支持 函數表達式,運算符表達式 ,這兩種類型的表達式 用的是 同一個 抽象思想;
Student stu01 = new Student { Name = "舒小龍", Number = "ShuXiaolong"}; Student stu02 = new Student { Name = "張三", Number = "zhangsan" }; Student stu03 = new Student { Name = "舒珊", Number = "ShuShan" }; ExpressSchema expressSchema = ExpressSchema.Create("[Number] LIKE '%Shu%'"); bool result1_1 = (bool) expressSchema.Compute(stu01); bool result1_2 = (bool)expressSchema.Compute(stu02); bool result1_3 = (bool)expressSchema.Compute(stu03); Console.WriteLine(result1_1 + "|" + result1_2 + "|" + result1_3); ExpressSchema expressSchema2 = ExpressSchema.Create("[Name] + [Number]"); string result2_1 = (string)expressSchema2.Compute(stu01); string result2_2 = (string)expressSchema2.Compute(stu02); string result2_3 = (string)expressSchema2.Compute(stu03); Console.WriteLine(result2_1 + "|" + result2_2 + "|" + result2_3);

DataSet dataSet = GetTableRecord(); //從數據庫 讀取 50000 個單詞 DataTable dataWord = dataSet.Tables[0]; DateTime dt7 = DateTime.Now; IList listResult3 = ComputeHelper.Sort("[Word],[Comment]", dataWord.Rows); //用封裝好的 排序函數 排序 DateTime dt8 = DateTime.Now; Console.WriteLine("ComputeHelper.Sort()排序時間:" + (dt8 - dt7).TotalMilliseconds); Console.WriteLine(listResult3);

DataSet dataSet = GetTableRecord(); //從數據庫 讀取 50000 個單詞 DataTable dataWord = dataSet.Tables[0]; DateTime dt7 = DateTime.Now; IList listResult3 = ComputeHelper.Filter("[Word] LIKE '%cat%'", dataWord.Rows); //用封裝好的 篩選函數 篩選 DateTime dt8 = DateTime.Now; Console.WriteLine("ComputeHelper.Filter()篩選時間:" + (dt8 - dt7).TotalMilliseconds); Console.WriteLine(listResult3 + " 數目:" + listResult3.Count);

比方說 擴展一個 三元運算符 的插件:
在 任何程序集, 任何命名空間, 任何類名稱 下,引用 Laura.Compute.dll
1 using System; 2 3 namespace 任意命名空間 4 { 5 [Serializable] 6 [ComputeExpress(Express = "{A} ? {A} : {A}", Keywords = new[] { "?", ":" }, Level = 100, ComputeType = typeof(TernaryComputeSymbol))] 7 public class TernaryComputeSymbol : ComputeBase 8 { 9 public override object Compute(ExpressSchema expressSchema, object objOrHash) 10 { 11 bool arg1 = ArgumentsBoolean(0, expressSchema, objOrHash); //獲取第一個 bool參數 12 //if (Arguments[1].Type != Arguments[2].Type) 13 // throw new Exception("TernaryComputeSymbol Type Is Not Same!"); 14 15 //完全省略 多余計算 16 string value = arg1 17 ? ArgumentsString(1, expressSchema, objOrHash) //計算 第一個部分 的表達式 18 : ArgumentsString(2, expressSchema, objOrHash); //計算 第二個部分 的表達式 19 20 21 return value; 22 } 23 } 24 }
擴展一個插件 就這么簡單!
Ps. 最好是能將源碼 發不到某個 網絡版本控制器上,但是不知道 如何操作,也不知道哪個 哪個平台 有 SVN的版本控制器;
如果哪位有好的 網絡版本控制器,希望推薦一哈——還是放到 版本控制器中 開源 比較好;
