Картинка блога

DLR — это дополнительная обложка, написанная на C#, предназначенная для интерпретации скриптовых языков. Среди пионеров — IronPython и IronRuby. Теоретически, можно добавить любой другой интерпретируемый язык, сделав его совместимым с библиотеками .NET. Так как я чувствую в этом некоторый потенциал к расширяемости приложений, то решил изучить этот момент. В большинстве статей сделано описание того, как просто стало писать приложения на скриптовых языках, используя при это .NET библиотеки. Для меня более ценным кажется обратная возможность — запуск и управление скриптом из C# (Script Hosting).

Последнее время, стало модно выпускать различные beta и preview версии библиотек. Хорошие идеи быстро подхватываются сообществами и блогеры начинают строчить тонны текста с примерами кода. Но через некоторое время выходит окончательный релиз, с большим количеством рефакторинга, после чего примеры и описанные способы перестают работать. А блоги с устаревшей информацией продолжают нравится гуглу, окончательно запутывая программиста исследователя.

Хоть основная работа по DLR и IronPython завершена, некоторые изменения в API все еще ожидаются. На данный момент, самым исчерпывающим и достоверным источником на мой взгляд является официальная спецификация DLR (на поставленный вопрос отвечает dlr-spec-hosting.pdf)

Установка

Я пользуюсь экспресс версией Visual C# 2010. Потребовалось некоторое время, чтобы понять какие DLL мне нужны. Для начала, нужно скачать и установить какой-нибудь IronЧтото. Так как я больше знаком с питоном, поставил IronPython. Никаких новых библиотек в GAC или шаблонов в студию мне это не дало. Зато все нужные библиотеки расположились в папке приложения: Microsoft.Scripting и IronPython. Добавляем их в ссылки проекта.

Чтобы облегчить конфигурирование языков, предусмотрена конфигурационная секция. Мой App.Config выглядит следующим образом:


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <configSections>
 <section name="microsoft.scripting" requirePermission="false" type="Microsoft.Scripting.Hosting.Configuration.Section, Microsoft.Scripting"/>
 </configSections>

 <microsoft.scripting>
 <languages>
 <language extensions=".py" displayName="IronPython 2.6.1" type="IronPython.Runtime.PythonContext, IronPython" names="IronPython;Python;py"/>
 </languages>
 </microsoft.scripting>
</configuration>

И мои два тестовых файла:

Program.cs:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Scripting.Hosting;

namespace ConsoleDLR
{
 public class MyContext
 {
 // получение переменной
 // если переменная Private, интерпретатор скажет, что она отсутствует.
 public string name = "name";

 // метод для вызова из python
 public void Bye()
 {
 Console.WriteLine("byebye");
 }
 }
 class Program
 {
 // точка входа
 static void Main(string[] args)
 {
 // читаем конфигурационную секцию
 var scriptRuntime = ScriptRuntime.CreateFromConfiguration();

 // добавляем глобальный объект
 scriptRuntime.Globals.SetVariable("obj", new MyContext());

 // загрузка файла, в нашем случае работает также как и ExecuteFile
 var scope = scriptRuntime.UseFile("hello.py");

 // вызвать функцию их файла
 scriptRuntime.Operations.Call(scope.GetVariable("hello"));

 // инстанцировать файл и вызвать его методы
 var helloInstance = scriptRuntime.Operations.CreateInstance(scope.GetVariable("Hello"));
 helloInstance.hello();
 helloInstance.tt(new MyContext());

 Console.Read();
 }
 //подобие dir()
 public static void ListVariables(ScriptScope scope)
 {
 foreach (string id in scope.GetVariableNames())
 {
 dynamic fun;
 bool got_fun = scope.TryGetVariable(id, out fun);
 if (got_fun)
 {
 Console.WriteLine(id + " " + fun);
 }
 }

 }
 }
}

И, соответственно «hello.py» (в свойствах укажите, чтобы студия скопировала его в bin папку):


# импорт глобального объекта. иначе скрипт о нем не знает
import obj

# функция для вызова
def hello():
	print "def world"

# класс для инстанцирования
class Hello:
	def __init__(self):
		print "class init"
	def hello(self):
		print "class hello"

	def tt(self, obj):
		obj.Bye()
		print dir(obj)
		print obj.name

# это выполнится в самом начале
print "Hello world"
print obj

Теперь все готово. На выходе получается


Hello world
<ConsoleDLR.MyContext object at 0x000000000000002B [ConsoleDLR.MyContext]>
def world
class init
class hello
byebye
['Bye', '__class__', '__delattr__', '__doc__', '__format__', '__getattribute__',
 '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '
__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'name']
name

Это только маленькая часть того, как можно работать с DLR. В спецификации описано большое количество, запутанных на первый взгляд, приемов. Лично я привык делать так, как быстрей и проще.  Надеюсь я помог не запутаться в начале его изучения.

Метки:, , ,