일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 다트 언어
- git
- 유니티
- 포인터
- vim
- jupyter
- Data Structure
- c# winform
- 플러터
- jupyter lab
- Python
- Houdini
- c#
- c# 추상 클래스
- C++
- c# 윈폼
- C언어 포인터
- gitlab
- c언어
- dart 언어
- docker
- 깃
- Algorithm
- 구조체
- C# delegate
- Unity
- HTML
- github
- 도커
- Flutter
- Today
- Total
nomad-programmer
[Programming/C#] 동적 언어와의 상호 운용성을 위한 dynamic 형식 본문
파이썬(Python)과 루비(Ruby)는 최근 유행하고 있는 동적 언어(Dynamic Language 또는 Dynamic Typed Language)이다.
CLR(Common Language Runtime) 은 IL(Intermediate Language)로 컴파일할 수 있는 언어들은 지원하지만, 파이썬이나 루비처럼 실행할 때 코드를 해석해서 실행하는 방식의 동적 언어는 지원할 수 없다. 그래서 마이크로소프트는 동적 언어를 실행할 수 있도록 해주는 플랫폼인 DLR(Dynamic Language Runtime)을 선보였다.
DLR은 CRL위에서 동적하며, 파이썬이나 루비와 같은 동적 언어를 실행할 수 있다. DLR의 장점은 그저 동적 언어를 .NET 플랫폼에서 실행할 수 있다는 정도에서 그치지 않는다. DLR은 파이썬이나 루비 같은 동적 언어의 코드에서 만들어진 객체에 C#이나 VB같은 정적 언어의 코드에서 접근할 수 있게 해준다. 한마디로, C#코드에서 직접 파이썬이나 루비 코드를 실행하고 그 결과를 받아볼 수 있다는 이야기이다.
또한 CLR 입장에서 보면 DLR API를 기반으로 구현된 동적 언어라도 호스팅(Hosting) 할 수 있다는 장점이 있다. 가령 파이썬을 줄곧 사용해오다 파이썬에는 없는 라이브러리가 루비에 있는 경우, C# 프로그래머는 별도의 학습 없이도 바로 루비 라이브러리를 이용하는 코드를 호스팅할 수 있다.
COM과 .NET의 상호 운용성 문제에 사용했던 dynamic을 CLR과 DLR 사이의 상호 운용성 문제을 해결하는데 사용할 수 있다. 미리 형식 검사를 할 수 없는 동적 형식 언어에서 만들어진 객체를 C#의 dynamic 형식이 받아낼 수 있기때문이다.
클래스 | 설명 |
ScriptRuntime | 동적 언어를 호스팅하는 시작점. ScriptRuntime 클래스는 참조된 어셀브리나 전역 객체 같은 전역 상태를 나타내며 하나의 .NET AppDomain 안에 여러 개의 ScriptRuntime 인스턴스를 만들 수 있다. |
ScriptScope | 기본적으로 네임스페이스를 나타낸다. 호스트(즉, C# 코드)는 ScriptScope 객체 안에 동적 언어 코드에서 사용하는 변수에 값을 대입하거나 읽을 수 있다. |
ScriptEngine | 스크립트 엔진은 언어의 구문을 나타내는 일꾼이다. 스크립트 엔진은 코드를 실행하고 ScriptScope와 ScriptSource를 생성하는 다양한 방법을 제공한다. |
ScriptSource | 이 클래스는 소스 코드를 읽어들이는 여러 메소드와 읽어들인 소스 코드를 다양한 방법으로 실행하는 메소드들을 제공한다. |
CompiledCode | 이 클래스는 컴파일된 코드를 나타낸다. 한번 컴파일해놓고 여러 번 반복해서 실행하는 코드를 나타내는 데 사용된다. |
위 표의 클래스들은 C# 호스트 코드에서 게스트 코드를 실행할 때 다양한 방법으로 조합하여 사용할 수 있다. 우선 ScriptRuntime 객체는 소스 코드 "파일"의 경로를 넘겨받아 실행할 수 있다.
// 파이썬 소스 코드 파일을 ScriptRuntime 객체가 읽어 실행하는 예
ScriptRuntime runtime = Python.CreateRuntime();
dynamic result = runtime.ExcuteFile("namecard.py");
프로그램을 실행할 때 생성한 문자열에 담긴 동적 언어 코드도 실행할 수 있다. ScriptEngine, ScriptScope, ScriptSource 클래스를 이용하면 된다.
// 문자열에 담겨 있는 파이썬 코드를 실행하는 예
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
scope.SetVariable("n", "test");
scope.SetVariable("p", "000-123-1234");
ScriptSource source = engine.CreateScriptSourceFromString(
@"
class NameCard:
name = ''
phone = ''
def __init__(self, name, phone):
self.name = name
self.phone = phone
def print_name(self):
print('{0}, {1}'.format(self.name, self.phone))
NameCard(n, p)
");
dynamic result = source.Execute(scope);
result.print_name();
Console.WriteLine("{0}, {1}", result.name, result.phone);
마지막 줄에서 dynamic 형식은 ScriptRuntime을 이용해서 소스 파일에 담긴 코드를 실행하든 ScriptEngine, ScriptScope, ScriptSource를 이용해서 문자열에 담긴 코드를 그 자리에서 실행하든 C# 코드가 호스팅하고 있는 파이썬 코드 안에서 만들어진 객체를 그대로 받아낸다. 이렇게 받아낸 파이썬 출신의 객체는 C# 코드에서 직접 메소드를 호출할 수도 있고 필드에 접근하는 것도 가능하다.
C#에서 Python운용하는 예제
1. IronPython은 다운받고 설치한다. IronPython은 .NET Framework에서 구동이 가능한 파이썬 엔진이라고 생각하면 된다.
2. C# 콘솔 프로젝트를 만든다.
3. WithPython 프로젝트에 DLR과 IronPython 어셈블리를 추가하자. 솔루션 탐색기에서 WithPYthon 프로젝트의 '참조' 항목에서 마우스 우측 클릭 후 컨텍스트 메뉴를 띄운다. 그 후 '참조 추가' 항목을 클릭한다. 다음과 같이 참조 추가 창이 나타나면 [찾아보기] 탭을 선택하여 아이언 파이썬이 설치된 디렉토리를 찾아 다음 그림과 같이 다섯 개의 어셈블리(IronPython.dll, IronPython.Modules.dll, Microsoft.Dynamic.dll, Microsoft.Scripting.dll, Microsoft.Scripting.Metadata.dll) 를 선택한다.
4. WithPython 프로젝트의 Program.cs 파일의 이름을 MainApp.cs로 변경하고 코드를 작성한다.
using System;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
namespace WithPython
{
class MainApp
{
static void Main(string[] args)
{
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
scope.SetVariable("n", "testName");
scope.SetVariable("p", "000-123-1234");
ScriptSource source = engine.CreateScriptSourceFromString(
@"
class NameCard:
name = ''
phone = ''
def __init__(self, name, phone):
self.name = name
self.phone = phone
def print_namecard(self):
print '{0}, {1}'.format(self.name, self.phone)
NameCard(n, p)
");
dynamic result = source.Execute(scope);
result.print_namecard();
Console.WriteLine("{0}, {1}", result.name, result.phone);
}
}
}
/* 결과
testName, 000-123-1234
testName, 000-123-1234
*/
'Programming > C#' 카테고리의 다른 글
[Programming/C#] 스트림 (Stream) (0) | 2020.09.28 |
---|---|
[Programming/C#] 파일과 디렉토리 (0) | 2020.09.27 |
[Programming/C#] COM (Component Object Model) (0) | 2020.09.27 |
[Programming/C#] dynamic 형식 (0) | 2020.09.26 |
[Programming/C#] 어트리뷰트 (Attribute) (0) | 2020.09.26 |