在上一篇隨筆“再談 C# 互動視窗”6樓的評論中,DiryBoy 園友指出 csharp.exe 在 Windows 作業系統中運行出錯貌似 .NET 4 新的安全規則在作怪,並給出一個解決類似問題的網址。具體原因是 .NET Framework 4 中引入了兩級透明度,.NET Framework 4 規則使用第二級透明度(SecurityRuleSet.Level2),而 .NET Framework 2.0 規則使用第一級透明度(SecurityRuleSet.Level1)。所以在 Mono.CSharp.dll 的 C# 來源程式代碼的 AssemblyInfo.cs 檔案檔案中加入以下語句就可以解決這個問題:
[assembly: SecurityRules(SecurityRuleSet.Level1)]
但是這樣一來在 Ubuntu 作業系統中使用 mono 編譯就無法通過了。
mono 2.8.1 中和 csharp.exe 和 Mono.CSharp.dll 相關的 C# 來源程式總共只有六十個左右,分布在以下目錄中:
Mono.CSharp.dll 需要以下57個 C# 源檔案:
..\..\mcs\anonymous.cs..\..\mcs\argument.cs..\..\mcs\assign.cs..\..\mcs\attribute.cs..\..\mcs\cs-tokenizer.cs..\..\mcs\cfold.cs..\..\mcs\class.cs..\..\mcs\codegen.cs..\..\mcs\complete.cs..\..\mcs\const.cs..\..\mcs\constant.cs..\..\mcs\convert.cs..\..\mcs\context.cs..\..\mcs\decl.cs..\..\mcs\delegate.cs..\..\mcs\doc.cs..\..\mcs\doc-bootstrap.cs..\..\mcs\driver.cs..\..\mcs\dynamic.cs..\..\mcs\ecore.cs..\..\mcs\enum.cs..\..\mcs\eval.cs..\..\mcs\expression.cs..\..\mcs\field.cs..\..\mcs\flowanalysis.cs..\..\mcs\generic.cs..\..\mcs\import.cs..\..\mcs\iterators.cs..\..\mcs\lambda.cs..\..\mcs\linq.cs..\..\mcs\literal.cs..\..\mcs\location.cs..\..\mcs\membercache.cs..\..\mcs\method.cs..\..\mcs\modifiers.cs..\..\mcs\namespace.cs..\..\mcs\nullable.cs..\..\mcs\parameter.cs..\..\mcs\pending.cs..\..\mcs\property.cs..\..\mcs\report.cs..\..\mcs\rootcontext.cs..\..\mcs\roottypes.cs..\..\mcs\statement.cs..\..\mcs\support.cs..\..\mcs\typemanager.cs..\..\mcs\typespec.cs..\..\mcs\visit.cs..\..\mcs\symbolwriter.cs..\..\class\Mono.CompilerServices.SymbolWriter\MonoSymbolFile.cs..\..\class\Mono.CompilerServices.SymbolWriter\MonoSymbolTable.cs..\..\class\Mono.CompilerServices.SymbolWriter\MonoSymbolWriter.cs..\..\class\corlib\Mono.Security.Cryptography\CryptoConvert.cs..\..\build\common\Consts.cs..\..\tools\monop\outline.cs..\..\mcs\cs-parser.csAssembly\AssemblyInfo.cs
這是 mcs/class/Mono.CSharp.dll.sources 檔案的內容。注意在該檔案中的目錄分隔字元原來是 Linux 作業系統的“/”,現在被我替換為 Windows 作業系統的“\”。
而 csharp.exe 只需要以下三個 C# 源檔案:
..\..\class\corlib\Mono\DataConverter.csrepl.csgetline.cs
這是 mcs/tools/csharp/csharp.exe.sources 檔案的內容。然後,參照上一篇隨筆,在 mcs/tools/csharp/repl.cs 檔案第 59 行後加入以下一句:
Console.WriteLine(ex);
現在,編輯以下 mak.cmd 檔案用來編譯:
@echo offcd mcs\class\Mono.CSharpcsc -t:library -out:..\..\..\Mono.CSharp.dll -D:NET_4_0 @Mono.CSharp.dll.sources > ..\..\..\Mono.CSharp.txtcd ..\..\tools\csharpcsc /unsafe -out:..\..\..\csharp.exe -D:ON_DOTNET -r:..\..\..\Mono.CSharp.dll @csharp.exe.sources > ..\..\..\csharp.exe.txtcd ..\..\..sn -R Mono.CSharp.dll mcs\class\mono.snk > sn.txt
編譯和運行結果如下:
E:\CS\CsharpRepl\mono> makE:\CS\CsharpRepl\mono> csharpSystem.TypeLoadException: 重寫成員“Mono.CSharp.StreamReportPrinter.Print(Mono.CSharp.AbstractMessage)”時違反了繼承安全性規則。重寫方法的安全可訪問性必須與所重寫方法的安全可訪問性匹配。 在 Mono.CSharp.Evaluator.InitAndGetStartupFiles(String[] args) 在 Mono.Driver.Startup(String[] args)E:\CS\CsharpRepl\mono>
這和上一篇隨筆中的出錯情況一樣。現在讓我們在 mcs/class/Mono.CSharp/Assembly/AssemblyInfo.cs 檔案檔案中加入以下語句:
[assembly: SecurityRules(SecurityRuleSet.Level1)]
然後重新編譯,運行:
E:\CS\CsharpRepl\mono> makE:\CS\CsharpRepl\mono> csharp --versionMono C# compiler version 4.0.0.0E:\CS\CsharpRepl\mono> csharpMono C# Shell, type "help;" for helpEnter statements below.csharp> Environment.OSVersion;Microsoft Windows NT 6.0.6002 Service Pack 2csharp> Environment.Version;4.0.30319.1csharp> quit;E:\CS\CsharpRepl\mono>
終於在 Windows 作業系統下實現了 C# 互動視窗,並且沒有安裝 mono,而是只需要 Mono.CSharp.dll 和 csharp.exe 兩個檔案就可以了。
此外,還可以將 Mono.CSharp.dll 加入到全域組件快取中(需要管理員權限):
E:\CS\CsharpRepl\mono> gacutil /i Mono.CSharp.dllMicrosoft (R) .NET Global Assembly Cache Utility. Version 4.0.30319.1著作權(C) Microsoft Corporation。著作權所有,並保留一切權利。程式集已成功添加到緩衝中E:\CS\CsharpRepl\mono> gacutil /l Mono.CSharpMicrosoft (R) .NET Global Assembly Cache Utility. Version 4.0.30319.1著作權(C) Microsoft Corporation。著作權所有,並保留一切權利。全域組件快取包含下列程式集: Mono.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL項目數 = 1E:\CS\CsharpRepl\mono>
這樣之後再將 csharp.exe 放到 PATH 中的目錄裡,就可以隨時隨處運行 C# 互動視窗了。
最後,本文提到的所有程式都可以點擊這裡下載。