用著.NET Framework,發現了CodeDom的先天性缺陷,心裡百般難受。
不知道 CodeDom 是什麼的請看這裡 CodeDom_百度百科
這裡有CodeDom非常全的中文教程 CodeDOM - 隨筆分類 - lichdr - 博客園
首先說,CodeDom的思想非常好,把代碼當作研究的對象,用對象來表示代碼,這為代碼的動態處理提供了方便的可能。
CodeDom 的類型非常多,非常難以記得,經常憑著感覺組裝CodeDom,卻往往在幾個很類似的類的選取時被迷惑了,特別是CodeTypeReference和CodeTypeReferenceExpression,還有很特別的CodeExpressionStatement。單看MSDN的注釋非常抽象,幸好有勤勞的朋友作了整理。微軟CodeDom模型學習筆記(全) - 賽提斯特 - 博客園
本次是我第N次接觸CodeDom,我深知CodeDom寫起來非常繁瑣,所以本次我作了簡單的封裝,於是用起來簡潔多了。
//創建一個對象 var NewDbContext = Code.Var("MyDbContext", "db", Code.New("MyDbContext")).Value; var NewUser = Code.Var("User", "newUser", Code.New("User")).Value; //調用一個方法 //db.Users.Add(newUser); var db_Users_Add = Code.Var("db").Property("Users").Method("Add", Code.Var("newUser")).Value; //db.SaveChanges(); var db_SaveChanges = Code.Var("db").Method("SaveChanges"); //if(!db.SaveChanges(...)){ ... } else { ... } var If = Code.If(db_SaveChanges.Not()) .Then(Code.Class("Console").Method("WriteLine", Code.ConstValue("Register failed.")).AsStatement()) .Else(Code.Class("Console").Method("WriteLine", Code.ConstValue("Register Success.")).AsStatement()) .Value; var codes = new CodeStatementCollection(); codes.Add(NewDbContext); codes.Add(NewUser); codes.Add(db_Users_Add); codes.Add(If);
而在以前是這樣寫的:
CodeMemberMethod method = new CodeMemberMethod();//方法聲明; method.Name = "SayHello";// 方法名 method.Attributes = MemberAttributes.Public| MemberAttributes.Final;//屬性 method.ReturnType = new CodeTypeReference(typeof(string));//返回類型 method.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression("Hello from code!")));//方法體,只有一句返回語句return "Hello from code!"; CodeEntryPointMethod main = new CodeEntryPointMethod();//主方法Main main.Statements.Add(new CodeVariableDeclarationStatement("HelloWord","hw", new CodeObjectCreateExpression("HelloWord", new CodeExpression[] { })));//變量聲明:HelloWord hw = new HelloWord(); CodeMethodInvokeExpression methodinvoke= new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("hw"),"SayHello",new CodeExpression[]{}); main.Statements.Add(new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("System.Console"),"WriteLine", methodinvoke)); main.Statements.Add(new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("System.Console"), "Read"));//兩個方法調用:System.Console.WriteLine(hw.SayHello()); CodeTypeDeclaration helloword = new CodeTypeDeclaration("HelloWord");//類型Class聲明 helloword.Attributes = MemberAttributes.Public; helloword.Members.AddRange(new CodeTypeMember[]{method,main});//添加方法到clss CodeNamespace nspace = new CodeNamespace("HelloDemo1");//命名空間聲明 nspace.Imports.Add(new CodeNamespaceImport("System"));//引入程序命名空間:using System; nspace.Types.Add(helloword);
內容不對應,這裡只是為了說明有封裝和沒封裝的區別有多大。
可惜,一些“小”問題要找答案要找很久,要命的是,最終沒有答案、/抓狂。最近就遇到了一個最簡單的小到不能再小的問題,如何表示“邏輯非”運算,沒錯,就是C#中的感歎號(!),找了老半天,還請了高人朋友幫找,沒有。也許有人說Snippets就可以,但如果在這樣的一個封裝中:輸入一個Expression,把它包一層“非”成為新的Expression返回,Snippets也只能哭著說臣妾做不到啊。
看看這個 動態生成與編譯(九)----CodeDOM的局限 - lichdr - 博客園 局限性還是不少的。
最重要重要的一點,CSharpCodeProvider.Parse沒有實現,所有語言的Parse方法都沒有實現,可惡的Microsoft,竟然不提供解析器!試驗了所有的codeProvider,結果都是一樣,這絕對是微軟故意搞的,
想起幾次研究項目都停止了,現在想想每次都是止於CodeDom,原來根源在此。所以,我將目光投向了NRefacotry,據文檔說它非常強大。感謝 賽提斯特 的文章指引了這個好東西,不說了。我要去學習NRefacotry了。這玩意都是英文的,難啃啊。再次鄙視一下微軟的CodeDom,不好好做,做到一半,不完整,破滅了它在我心中的美好形象。
此文紀念我心中美好的System.CodeDom的死去。