[翻译] metaprogramming with autocad (二) - 精华帖集合
www.dimcax.com
[翻译] metaprogramming with autocad (二)
上一篇文章我简要的介绍了利用autolisp和vb(a)中使用autocad元编程的技术,在这一篇文章里,我们将继续第一节的话题。接下来我们来看看.net如何实现,首先让我们把目光转向c#和vb.net。 ps:作者还有第三篇文章,用于介绍.net家族新的开发语言f#的元编程技术,大家如果有兴趣可以到kean的blog里面阅读,地址through-the-interface.typepad.com,在此我们略过。 .net不支持类似eval()函数的方法,但是,它提供的痛惜却更加有趣。clr提供了执行codedomprovider协议的用于编译和执行.net语言源代码的接口。 举例来说,microsoft.csharp 命名空间提供了允许你从其他.net语言编译c#原代码的csharpcodeprovider类;vb.net也一样,microsoft.visualbasic 包含了vbcodeprovider。 这就是说,我们可以很轻松的利用.net在homogeneous 或者heterogeneous 模式实现dynamic metaprogramming 。
下面是c#代码,实现编译和执行c#(homogeneous)和vb.net(heterogeneous)代码。 using autodesk.autocad.runtime; using autodesk.autocad.applicationservices; using autodesk.autocad.editorinput; using microsoft.csharp; using microsoft.visualbasic; using system.codedom.compiler; using system.reflection; using system.text; using system; namespace metaprogramming { public class commands { const string acadfolder = "c:\\program files\\autodesk\\autocad 2008\\"; // evalcs: evaluates c# source public static object evalcs(string cscode) { documentcollection dm = application.documentmanager; editor ed = dm.mdiactivedocument.editor; csharpcodeprovider cs = new csharpcodeprovider(); compilerparameters cp = new compilerparameters(); cp.referencedassemblies.add("system.dll"); cp.referencedassemblies.add(acadfolder + "acdbmgd.dll"); cp.referencedassemblies.add(acadfolder + "acmgd.dll"); cp.compileroptions = "/t:library"; cp.generateinmemory = true; stringbuilder sb = new stringbuilder(); sb.append("using system;\n"); sb.append("using autodesk.autocad.runtime;\n"); sb.append( "using autodesk.autocad.applicationservices;\n" ); sb.append("using autodesk.autocad.databaseservices;\n"); sb.append("using autodesk.autocad.editorinput;\n"); sb.append("using autodesk.autocad.geometry;\n"); sb.append("namespace cscodeeval{\n"); sb.append("public class cscodeeval{\n"); sb.append("public object evalcode(){\n"); sb.append("return " + cscode + ";\n"); sb.append("}\n"); sb.append("}\n"); sb.append("}\n"); compilerresults cr = cs.compileassemblyfromsource(cp, sb.tostring()); if (cr.errors.count > 0) { ed.writemessage( "\nerrors evaluating c# code (" + cr.errors.count + "):" ); for (int i = 0; i < cr.errors.count; i++) { ed.writemessage( "\nline number " + cr.errors.line + ": " + cr.errors.errortext ); } return null; } system.reflection.assembly a = cr.compiledassembly; object o = a.createinstance("cscodeeval.cscodeeval"); type t = o.gettype(); methodinfo mi = t.getmethod("evalcode"); object s = mi.invoke(o, null); return s; } // evalvb: evaluates vb source public static object evalvb(string vbcode) { documentcollection dm = application.documentmanager; editor ed = dm.mdiactivedocument.editor; vbcodeprovider vb = new vbcodeprovider(); compilerparameters cp = new compilerparameters(); cp.referencedassemblies.add("system.dll"); cp.referencedassemblies.add(acadfolder + "acdbmgd.dll"); cp.referencedassemblies.add(acadfolder + "acmgd.dll"); cp.compileroptions = "/t:library"; cp.generateinmemory = true; stringbuilder sb = new stringbuilder(); sb.append("imports system\n"); sb.append("imports autodesk.autocad.runtime\n"); sb.append( "imports autodesk.autocad.applicationservices\n" ); sb.append( "imports autodesk.autocad.databaseservices\n" ); sb.append("imports autodesk.autocad.editorinput\n"); sb.append("imports autodesk.autocad.geometry\n"); sb.append("namespace vbcodeeval\n"); sb.append("public class vbcodeeval\n"); sb.append("public function evalcode() as object\n"); sb.append("return " + vbcode + " \n"); sb.append("end function\n"); sb.append("end class\n"); sb.append("end namespace\n"); compilerresults cr = vb.compileassemblyfromsource(cp, sb.tostring()); if (cr.errors.count > 0) { ed.writemessage( "\nerrors evaluating vb code (" + cr.errors.count + "):" ); for (int i = 0; i < cr.errors.count; i++) { ed.writemessage( "\nline number " + cr.errors.line + ": " + cr.errors.errortext ); } return null; } system.reflection.assembly a = cr.compiledassembly; object o = a.createinstance("vbcodeeval.vbcodeeval"); type t = o.gettype(); methodinfo mi = t.getmethod("evalcode"); object s = mi.invoke(o, null); return s; }
[commandmethod("ev")] public void eval() { documentcollection dm = application.documentmanager; editor ed = dm.mdiactivedocument.editor; const string cscode = "typeof(autodesk.autocad." + "applicationservices.application)"; const string vbcode = "gettype(autodesk.autocad." + "applicationservices.application)"; ed.writemessage("\nevaluating c# code:\n" + cscode); object result = evalcs(cscode); if (result != null) ed.writemessage( "\nc# code returned: " + result.tostring() ); ed.writemessage("\nevaluating vb code:\n" + vbcode); result = evalvb(vbcode); if (result != null) ed.writemessage( "\nvb code returned: " + result.tostring() ); } } }
vb.net源代码,实现同样的功能 imports autodesk.autocad.runtime imports autodesk.autocad.applicationservices imports autodesk.autocad.editorinput imports microsoft.csharp imports microsoft.visualbasic imports system.codedom.compiler imports system.reflection imports system.text imports system namespace metaprogramming public class commands private const acadfolder as string = _ "c:\\program files\\autodesk\\autocad 2008\\" 'evalcs: evaluates c# source public shared function evalcs(byval cscode as string) _ as object dim dm as documentcollection = _ application.documentmanager dim ed as editor = dm.mdiactivedocument.editor dim cs as csharpcodeprovider = new csharpcodeprovider dim cp as compilerparameters = new compilerparameters cp.referencedassemblies.add("system.dll") cp.referencedassemblies.add(acadfolder + "acdbmgd.dll") cp.referencedassemblies.add(acadfolder + "acmgd.dll") cp.compileroptions = "/t:library" cp.generateinmemory = true dim sb as stringbuilder = new stringbuilder sb.append("using system;" & vblf) sb.append("using autodesk.autocad.runtime;" & vblf) sb.append( _ "using autodesk.autocad.applicationservices;" & vblf) sb.append( _ "using autodesk.autocad.databaseservices;" & vblf) sb.append("using autodesk.autocad.editorinput;" & vblf) sb.append("using autodesk.autocad.geometry;" & vblf) sb.append("namespace cscodeeval{" & vblf) sb.append("public class cscodeeval{" & vblf) sb.append("public object evalcode(){" & vblf) sb.append("return " + cscode + ";" & vblf) sb.append("}" & vblf) sb.append("}" & vblf) sb.append("}" & vblf) dim cr as compilerresults = _ cs.compileassemblyfromsource(cp, sb.tostring) if (cr.errors.count > 0) then ed.writemessage( _ vblf & "errors evaluating c# code (" + _ cr.errors.count.tostring + "):") dim i as integer for i = 0 to cr.errors.count - 1 ed.writemessage( _ vblf & "line number " + _ cr.errors(i).line.tostring + ": " + _ cr.errors(i).errortext) next return nothing end if dim a as system.reflection.assembly = _ cr.compiledassembly dim o as object = _ a.createinstance("cscodeeval.cscodeeval") dim t as type = o.gettype dim mi as methodinfo = t.getmethod("evalcode") dim s as object = mi.invoke(o, nothing) return s end function 'evalvb: evaluates vb source public shared function evalvb(byval vbcode as string) _ as object dim dm as documentcollection = _ application.documentmanager dim ed as editor = dm.mdiactivedocument.editor dim vb as vbcodeprovider = new vbcodeprovider dim cp as compilerparameters = new compilerparameters cp.referencedassemblies.add("system.dll") cp.referencedassemblies.add(acadfolder + "acdbmgd.dll") cp.referencedassemblies.add(acadfolder + "acmgd.dll") cp.compileroptions = "/t:library" cp.generateinmemory = true dim sb as stringbuilder = new stringbuilder sb.append("imports system" & vblf) sb.append("imports autodesk.autocad.runtime" & vblf) sb.append( _ "imports autodesk.autocad.applicationservices" & vblf) sb.append( _ "imports autodesk.autocad.databaseservices" & vblf) sb.append("imports autodesk.autocad.editorinput" & vblf) sb.append("imports autodesk.autocad.geometry" & vblf) sb.append("namespace vbcodeeval" & vblf) sb.append("public class vbcodeeval" & vblf) sb.append("public function evalcode() as object" & vblf) sb.append("return " + vbcode + " " & vblf) sb.append("end function" & vblf) sb.append("end class" & vblf) sb.append("end namespace" & vblf) dim cr as compilerresults = _ vb.compileassemblyfromsource(cp, sb.tostring) if (cr.errors.count > 0) then ed.writemessage( _ vblf & "errors evaluating vb code (" + _ cr.errors.count.tostring + "):") dim i as integer for i = 0 to cr.errors.count - 1 ed.writemessage( _ vblf & "line number " + _ cr.errors(i).line.tostring + ": " + _ cr.errors(i).errortext) next return nothing end if
dim a as system.reflection.assembly = _ cr.compiledassembly dim o as object = _ a.createinstance("vbcodeeval.vbcodeeval") dim t as type = o.gettype dim mi as methodinfo = t.getmethod("evalcode") dim s as object = mi.invoke(o, nothing) return s end function "ev")> _ public sub eval() dim dm as documentcollection = _ application.documentmanager dim ed as editor = dm.mdiactivedocument.editor const cscode as string = _ "typeof(autodesk.autocad." + _ "applicationservices.application)" const vbcode as string = _ "gettype(autodesk.autocad." + _ "applicationservices.application)" ed.writemessage( _ vblf + "evaluating c# code:" + _ vblf + cscode) dim result as object = evalcs(cscode) if (not result is nothing) then ed.writemessage( _ vblf + "c# code returned: " + _ result.tostring) end if ed.writemessage( _ vblf + "evaluating vb code:" + _ vblf + vbcode) result = evalvb(vbcode) if (not result is nothing) then ed.writemessage( _ vblf + "vb code returned: " + _ result.tostring) end if end sub end class end namespace
运行结果: command: ev evaluating c# code: typeof(autodesk.autocad.applicationservices.application) c# code returned: autodesk.autocad.applicationservices.application evaluating vb code: gettype(autodesk.autocad.applicationservices.application) vb code returned: autodesk.autocad.applicationservices.application