검색결과 리스트
글
C#,JScript, VisualBasic 을 스크립트처럼 사용하기
설명
어떤 프로그램을 만들다 보면, 간혹 사용자로부터 소스코드를 입력받아 실행시켜야 하는 경우가 있습니다. 물론 이런 기능을 이용할 경우가 많치는 않지만요. :) 과연 가능할까요? 답부터 말씀 드리자면 가능합니다.
CodeDomProvider
아시다시피, .NET 은 인터프리터 언어가 아니라, 컴파일 언어입니다. 엄격히 말해, 스크립트로 실행되는게 아니라는 것이지요. 그럼 어떻게 하느냐? CodeDomProvider 라는 녀석을 이용해서, Runtime 시점에 코드를 빌드하고 실행하는 것입니다. 마치 스크립트로 동작하는 것 처럼 말이죠.
CodeComProvider 는 대표적으로 C#, JScript, VisualBasic 모두 지원합니다. 타 언어도 되는걸로 알고 있습니다만, 찾아보시기 바랍니다. :)
코드를 보여드리기 전에, 간략히 설명 드리자면...
1. 먼저 코드를 파일이나 string 형태로 받아와서 빌드를 합니다.
2. Assembly 를 얻습니다.
3. EnryPoint 를 통해서 실행하거나, Type 을 통해서 Instance 를 생성 후, 메소드를 호출합니다.
이런 구조입니다. 외부에서 인지하기에는 마치 스크립트로 동작하는 것 처럼 느낄 수 있습니다. 물론 빌드 속도가 엄청 느리지만 않다면 말이죠 :) 코드를 보시면 쉽게 이해 하실 수 있을 것 입니다.
[Sample Code]
public static void Main(string[] argv)
{
string[] code = new string[]
{
"using System;" +
"public class CSharScript {" +
"public static int Main() { return 10; }" +
"public static string StaticMethod() { return \"StaticMethod\"; }" +
"public string MemberMethod(string input) { return input; }" +
"}"
};
ExecuteScript(code);
}
static void ExecuteScript(string[] sources) {
// create provider (사용 후, Dispose 해주어야 합니다.)
using (CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp")) {
/* 이외에도 각 언어별 provider 가 존재합니다.
* CodeDomProvider provider = CodeDomProvider.CreateProvider("VisualBasic");
* CodeDomProvider provider = CodeDomProvider.CreateProvider("JScript");
*
*
* 필요에 따라, 아래처럼 직접 CSharpCodeprovider 를 생성해도 됩니다.
* CSharpCodeProvider provider = new CSharpCodeProvider();
* VBCodeProvider provider = new VBCodeProvider();
* JScriptCodeProvider provider = new JScriptCodeProvider();
*
* 하지만 전자쪽 방법을 추천드립니다. 문자열로 생성시 별도로 Assembly 를 추가할 필요도 없고,
* using 을 할 필요도 없는 반면, 후자 방식은 일일이 전부 추가해 주어야 합니다. :)
*/
CompilerParameters options = new CompilerParameters() {
//CompilerOptions = "/optimize",
GenerateExecutable = true, // 실행 가능하도록 만듦. 즉 Main 메소드가 있는 exe 파일 같이 만들거냐는 것입니다.
// false 인 경우, DLL 처럼 메소드 집합체(?)가 만들어 집니다.
GenerateInMemory = false,
MainClass = "CSharScript2",
IncludeDebugInformation = false,
TreatWarningsAsErrors = true
};
// Compile
CompilerResults results = provider.CompileAssemblyFromSource(options, sources);
if (results.Errors.Count > 0) {
string output = "Compile Error(s): ";
foreach (CompilerError error in results.Errors) {
output += string.Format("{0}{1}", Environment.NewLine, error.ErrorText);
}
throw new ArgumentException("Compile Error", output);
}
// GenerateExecutable 이 true 인 경우에만 EntryPoint 로 접근 가능합니다.
MethodInfo entryPoint = results.CompiledAssembly.EntryPoint;
Type mainClass = entryPoint.DeclaringType;
object result = entryPoint.Invoke(null, null);
Console.WriteLine("EntryPoint Result: " + result);
// GenerateExecutable 이 false 인 경우에도 가능합니다.
Type CSharpScriptClass = results.CompiledAssembly.GetType("CSharScript");
var instance = Activator.CreateInstance(CSharpScriptClass);
result = CSharpScriptClass.GetMethod("MemberMethod").Invoke(instance, new object[] { "Hello, World" });
Console.WriteLine("MemberMethod " + result);
// JScript 는 아래처럼 JScriptEvaluate 라는 static method 를 통해서 바로 실행할 수도 있습니다.
result = Microsoft.JScript.Eval.JScriptEvaluate(sources[0], Microsoft.JScript.Vsa.VsaEngine.CreateEngine());
}
}
'Microsoft > C#' 카테고리의 다른 글
Implicit Operator (0) | 2014.11.17 |
---|---|
BlockingQueue (0) | 2014.05.19 |
#warning, #error, #line 지시자 (0) | 2014.05.08 |
인증서(certification) 만들기 (1) | 2014.04.09 |
윈도우즈 방화벽 규칙 추가/설정/삭제하기 (3) | 2014.03.27 |
RECENT COMMENT