Eval 是一種動態引用程式碼的技術
相關技術:
*CodeDomProvider Class
*CompilerParameters Class
*Assembly Class
回目錄
* 檔案 Evaluates.cs
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Text;
using System.Reflection;
namespace System.CodeDom.Compiler
{
/// <summary>
/// 程式語言種類
/// </summary>
public enum LangType {
CSharp,
VisualBasic
}
public class Evaluates
{
/// <summary>
///
/// </summary>
/// <param name="type">程式語言種類</param>
/// <param name="code">封裝前的原始程式碼</param>
/// <param name="UsingNamespace">使用組件的命名空間</param>
/// <param name="NamespaceName">執行時的命名空間</param>
/// <param name="ClassName">執行時的類別名稱</param>
/// <param name="MethodName">執行時的函數名稱</param>
/// <param name="ParamsForamt">執行時的參數格式定義</param>
/// <returns></returns>
public static string GetEvalSource(
LangType type,
string code,
string [] UsingNamespace = null,
string NamespaceName = "DynameEval",
string ClassName = "Class1",
string MethodName = "Exec",
string ParamsForamt = "")
{
StringBuilder sb = new StringBuilder();
switch (type)
{
case LangType.CSharp:
{
sb.Append("using System;\n");
if (UsingNamespace != null)
{
foreach (string refUsing in UsingNamespace)
{
sb.AppendFormat("using {0};\n", refUsing);
}
}
sb.AppendFormat("namespace {0} { \n", NamespaceName);
sb.AppendFormat("public class {0} { \n", ClassName);
sb.AppendFormat("public object {0}({1}){\n", MethodName, ParamsForamt);
if (code.IndexOf("return") >=0)
{
sb.AppendFormat("{0}; \n", code);
}
else
{
sb.AppendFormat("return {0}; \n", code);
}
sb.Append("} \n");
sb.Append("} \n");
sb.Append("}\n");
}
break;
case LangType.VisualBasic:
{
sb.Append("Imports System\n");
sb.Append("Imports Microsoft.VisualBasic\n");
if (UsingNamespace != null)
{
foreach (string refUsing in UsingNamespace)
{
sb.AppendFormat("Imports {0}\n", refUsing);
}
}
sb.AppendFormat("Namespace {0}\n", NamespaceName);
sb.AppendFormat("Public Class {0}\n", ClassName);
sb.AppendFormat("Public Function {0}({1}) As Object\n", MethodName, ParamsForamt);
if (code.IndexOf("Return") >= 0)
{
sb.AppendFormat("{0} \n", code);
}
else
{
sb.AppendFormat("Return DirectCast({0}, Object) \n", code);
}
sb.Append("End Function\n");
sb.Append("End Class\n");
sb.Append("End Namespace\n");
}
break;
}
return sb.ToString();
}
/// <summary>
/// 從記憶體中的原始程式碼字串, 進行編譯與執行
/// </summary>
/// <param name="type">程式語言種類</param>
/// <param name="ErrorText">傳出編譯錯誤的原因</param>
/// <param name="code">原始程式碼</param>
/// <param name="ReferencedAssemblies">執行時需要載入的DLL檔, 不使用則用 null</param>
/// <param name="InstanceName">類別名稱(含命名空間)</param>
/// <param name="MethodName">要執行的函數名稱</param>
/// <param name="oParams">執行時傳入參數的陣列, 如果不使用傳入參數則用 null</param>
/// <returns>傳出執行的傳回值</returns>
public static object EvalFromSource(
LangType type,
ref string ErrorText,
string code,
string[] ReferencedAssemblies = null,
string InstanceName = "DynameEval.Class1",
string MethodName = "Exec",
object[] oParams = null)
{
string language = "";
CodeDomProvider provider = null;
switch (type)
{
case LangType.CSharp:
language = "CSharp";
break;
case LangType.VisualBasic:
language = "VisualBasic";
break;
}
if (CodeDomProvider.IsDefinedLanguage(language))
{
provider = CodeDomProvider.CreateProvider(language);
}
if (provider == null)
{
ErrorText = string.Format("無法載入{0}的CodeDomProvider", language);
return null;
}
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Core.dll");
if (type == LangType.VisualBasic)
{
cp.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll");
}
if (ReferencedAssemblies != null)
{
foreach (string refDll in ReferencedAssemblies)
{
cp.ReferencedAssemblies.Add(refDll);
}
}
cp.CompilerOptions = "/t:library";
cp.GenerateInMemory = true;
// Invoke compilation of the source code.
CompilerResults cr = provider.CompileAssemblyFromSource(cp, code);
if (cr.Errors.Count > 0)
{
ErrorText = cr.Errors[0].ErrorText;
return null;
}
ErrorText = "";
Assembly a = cr.CompiledAssembly;
object o = a.CreateInstance(InstanceName);
Type t = o.GetType();
MethodInfo mi = t.GetMethod(MethodName);
object s = mi.Invoke(o, oParams);
return s;
}
/// <summary>
/// 從程式碼的檔案, 進行編譯與執行
/// </summary>
/// <param name="type">程式語言種類</param>
/// <param name="ErrorText">傳出編譯錯誤的原因</param>
/// <param name="file">原始程式檔案</param>
/// <param name="ReferencedAssemblies">執行時需要載入的DLL檔, 不使用則用 null</param>
/// <param name="InstanceName">類別名稱(含命名空間)</param>
/// <param name="MethodName">要執行的函數名稱</param>
/// <param name="oParams">執行時傳入參數的陣列, 如果不使用傳入參數則用 null</param>
/// <returns>傳出執行的傳回值</returns>
public static object EvalFromFile(
LangType type,
ref string ErrorText,
string file,
string[] ReferencedAssemblies = null,
string InstanceName = "DynameEval.Class1",
string MethodName = "Exec",
object[] oParams = null)
{
string language = "";
CodeDomProvider provider = null;
switch (type)
{
case LangType.CSharp:
language = "CSharp";
break;
case LangType.VisualBasic:
language = "VisualBasic";
break;
}
if (CodeDomProvider.IsDefinedLanguage(language))
{
provider = CodeDomProvider.CreateProvider(language);
}
if (provider == null)
{
ErrorText = string.Format("無法載入{0}的CodeDomProvider", language);
return null;
}
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Core.dll");
if (type == LangType.VisualBasic)
{
cp.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll");
}
if (ReferencedAssemblies != null)
{
foreach (string refDll in ReferencedAssemblies)
{
cp.ReferencedAssemblies.Add(refDll);
}
}
cp.CompilerOptions = "/t:library";
cp.GenerateInMemory = true;
// Invoke compilation of the source code.
CompilerResults cr = provider.CompileAssemblyFromFile(cp, file);
if (cr.Errors.Count > 0)
{
ErrorText = cr.Errors[0].ErrorText;
return null;
}
ErrorText = "";
Assembly a = cr.CompiledAssembly;
object o = a.CreateInstance(InstanceName);
Type t = o.GetType();
MethodInfo mi = t.GetMethod(MethodName);
object s = mi.Invoke(o, oParams);
return s;
}
}
}