1. 「csproj文件究竟是做什麼用的」
csproj文件,即C#項目文件的擴展名,是"C Sharp Project"的縮寫。它主要用於為開發工具提供信息,比如我們熟悉的Visual Studio和MSBuild。Visual Studio會根據csproj中的XML定義來管理項目文件及相關數據,並執行各種操作。而MSBuild則會利用csproj文件來了解編譯這個項目需要哪些依賴項、默認輸出路徑、Pre-Build和Post-Build需要哪些操作等。
在開發環境中,csproj的存在是至關重要的,因為它為開發工具提供了必要的信息。然而,到了運行環境中,操作系統並不關心所謂的csproj文件,只關注exe、dll、配置文件或資源文件等實際運行時需要的東西。例如,IIS這樣的運行環境更不會去理會csproj的存在,因為它只需要web.config文件。
關於pdb文件是否需要放在Debug目錄下才有效的問題,其實是一個誤解。Debug目錄只是VS的模板所默認存在的編譯規則所生成的目錄,我們在調試時完全可以由VS指定pdb文件存在的目錄,甚至不需要VS也能使用pdb文件。
「模板」是開發環境中的重要組成部分,我們在VS中選擇New Item或New Project時可以看到各種模板。這些模板是人為生成給VS用的,可以自行學習如何建立一個模板。然而,在運行環境中,是不會知道開發中用了什麼模板的。
例如,為什麼Web Site中無法使用ASP.NET AJAX,而Web Application就可以?這與運行時期並沒有關系,而是與Web.config配置和頁面上的信息有關。很多時候,排錯並沒有什麼妙法,唯有仔細。
而「模板」在開發環境中的地位其實比csproj文件還要低。因為只要通過模板創建好內容之後,就無法說明結果和自己有什麼聯系了。例如使用模板創建一個AjaxControlToolkit的Extender,其中會生成一個.cs,一個.designer.cs和一個js文件,誰又能證明這三個文件不是我們手動創建的呢?這就是「開發環境」,一切都是為了提高開發效率,一切都是為了最終產生一個可執行的二進制文件。
開發環境中的最後一個成員「編譯器」工作完成之後,所有開發工具便默默地退居二線。
2. 如何用C#動態編譯,執行代碼 CSharpCodeProvider
如何用C#動態編譯、執行代碼
在開始之前,先熟悉幾個類及部分屬性、方法:CSharpCodeProvider、ICodeCompiler、CompilerParameters、CompilerResults、Assembly。
一、CSharpCodeProvider
提供對C#代碼生成器和代碼編譯器的實例的訪問。如果要動態生成VB代碼,可以使用VBCodeProvider。
CreateCompiler():獲取編譯器的實例。
二、ICodeCompiler
定義用於調用源代碼編譯的介面或使用指定編譯器的CodeDOM樹。每種編譯方法都接受指示編譯器的CompilerParameters對象,並返回指示編譯結果的CompilerResults對象。
CompilerAssemblyFromSource(CompilerParameters option, string source):使用指定的編譯器,從包含源代碼的字元串設置編譯程序集。
三、CompilerParameters
表示用於調用編譯器的參數。
ReferencedAssemblies:獲取當前項目所引用的程序集。Add方法為程序集添加引用。
GenerateExecutable:獲取或設置一個值,該值指示是否生成可執行文件。若此屬性為false,則生成DLL,默認是false。
GenerateInMemory:獲取或設置一個值,該值指示是否在內存中生成輸出。
四、CompilerResults
表示從編譯器返回的編譯結果。
CompiledAssembly:獲取或設置以編譯的程序集,Assembly類型。
五、Assembly
就是程序集了(不知道如何描述了)。
大致了解了以上知識之後,就可以使用C#動態的編譯並執行代碼了,一下是一段示常式序:
using System;
using System.Reflection;
using System.Globalization;
using Microsoft.CSharp;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Text;
namespace ConsoleApplication1
{
public class Program
{
static void Main(string[] args)
{
// 1.CSharpCodePrivoder
CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider();
// 2.ICodeComplier
ICodeCompiler objICodeCompiler = objCSharpCodePrivoder.CreateCompiler();
// 3.CompilerParameters
CompilerParameters objCompilerParameters = new CompilerParameters();
objCompilerParameters.ReferencedAssemblies.Add("System.dll");
objCompilerParameters.GenerateExecutable = false;
objCompilerParameters.GenerateInMemory = true;
// 4.CompilerResults
CompilerResults cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, GenerateCode());
if (cr.Errors.HasErrors)
{
Console.WriteLine("編譯錯誤:");
foreach (CompilerError err in cr.Errors)
{
Console.WriteLine(err.ErrorText);
}
}
else
{
// 通過反射,調用HelloWorld的實例
Assembly objAssembly = cr.CompiledAssembly;
object objHelloWorld = objAssembly.CreateInstance("DynamicCodeGenerate.HelloWorld");
MethodInfo objMI = objHelloWorld.GetType().GetMethod("OutPut");
Console.WriteLine(objMI.Invoke(objHelloWorld, null));
}
Console.ReadLine();
}
static string GenerateCode()
{
StringBuilder sb = new StringBuilder();
sb.Append("using System;");
sb.Append(Environment.NewLine);
sb.Append("namespace DynamicCodeGenerate");
sb.Append(Environment.NewLine);
sb.Append("{");
sb.Append(Environment.NewLine);
sb.Append(" public class HelloWorld");
sb.Append(Environment.NewLine);
sb.Append(" {");
sb.Append(Environment.NewLine);
sb.Append(" public string OutPut()");
sb.Append(Environment.NewLine);
sb.Append(" {");
sb.Append(Environment.NewLine);
sb.Append(" return \"Hello world!\";");
sb.Append(Environment.NewLine);
sb.Append(" }");
sb.Append(Environment.NewLine);
sb.Append(" }");
sb.Append(Environment.NewLine);
sb.Append("}");
string code = sb.ToString();
Console.WriteLine(code);
Console.WriteLine();
return code;
}
}
}