Программирование развивается очень активно, программы становятся все сложнее и сложнее и современные программисты все чаще и чаще обращаются к некой концепции, которую я хотел бы назвать концепцией "динамического кода". Давайте разовьем эту тему далее и обсудим все важные концепции.
В современных достаточно объемных программах статический скомпилированный код может оказаться недостаточно гибок для решения какой либо задачи, ведь статичность-это всегда статичность,никого вмешательства, только мертвый двоичный код, неизменный после компиляции программы. Расшатать его, внести нечто новое иное - вот что действительно вызывает интерес у программистов в наше время. Представьте себе - налету программа сама генерирует себя, вносит в себя всевозможные изменения и приобретает новые свойства!
Быть может, не все пока еще осознают преимущество данной концепции) Давайте рассмотрим пример программы, задача реализации которой может встать перед программистом.
Задача: В зависимости от каких либо внешних источников создать несколько экземпляров класса, записать данные и потом пользоваться ими.
Пояснение: То есть необходимо где то прочитать набор инструкций и поступить в соответствии с ними.
Пример простой реализации: Давайте разберем небольшой пример кода,как можно сделать решить данную задачу.
У нас есть файл,содержащий набор строк следующего вида
Бони,23,181,56778908
Игги,57,170,55432330
Заранее мы знаем,что здесь идет перечисление характеристик. Не представляется сложным счесть строки из файла в массив строк и обработать каждую строку (разбить на части по запятым, и каждую лексему записать как значение соответствующей переменной).
Как вы могли бы заметить, данный способ очень тривиальный, но не совсем гибкий. Достаточно поменять местами записи в файле и весь алгоритм собьется. Бедному Игги будет 170 лет,а то еще и 55432330 =)
Конечно, все в основном будут смотреть в сторону XML,что и правильно. Там все четко, параметры и привязанные к ним значения. Если параметров 100 - писать будете код долго,нудно и не интересно.Хочется гибкости. Динамичности. Как если бы на лету компилировалась программа,опираясь на внешние источники в виде текстовых файлов.....)
Конечно, пример,приведенный выше-не самый яркий пример острой потребности в "динамическом коде", но такая проблема тоже может встать и при помощи этого метода вполне просто решится)
Динамический код нужен тогда,когда хорошо бы было на лету сгенерировать классы, не обращаясь к рефлексии, создать динамически экземпляры классов с именами,которых нет в коде исходной программы вообще, выполнить какие нибудь инструкции, которые человек захочет поменять (а двоичный код программы поменять невозможно). Вот тогда то и мы подходим вплотную в нашему вопросу.
Встроенный интерпретатор, способный напрямую взаимодействовать с объектами кода C#. Свой язык программирования в вашей программе. Продвинутый редактор скриптов в движке игры. Динамический компилируемый исполняемый код, тесно взаимодействующий с вашей программой, ее полями, методами, классами, пространствами имен. Все это-концепция динамического кода.
В наше время есть множество наработок, связанных с различными встраиваемыми языками программирования. Я хочу рассмотреть наиболее приглянувшийся и развивающийся комплекс модулей под названием IronPython. IronPython - динамически компилируемый код, взаимодействующий с CLR, работающий в среде .NET Framework и способный к полному взаимодействию с ней. По сути-вариация языка Python, любимого веб-программистами.
Более подробно с его описанием можно ознакомится на официальном сайте http://ironpython.net/
Там же есть и официальная документация на английском языке.
Для работы с ним нам понадобится скачать исходники IronPython и взять необходимые нам dll.
Исходники находятся здесь http://ironpython.codeplex.com/releases/view/54498#DownloadId=216705 (если вы используете Visual Studio 2008, то вам нужна более старая версия,а именно http://ironpython.codeplex.com/releases/view/12482#DownloadId=96607 )
После скачивания и распаковки в корневом каталоге будут содержаться все необходимые нам модули
IronPython.dll
IronPython.Modules.dll
Microsoft.Scripting.dll
Microsoft.Scripting.Debugging.dll
Их будет необходимо добавить в наш проект ( Project-Add Reference...)
Далее необходимо внести в директивы using использование соответствующих пространств имен
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
Предварительно мы подготовили почву для работы. Далее необходимо будет объявить несколько экземпляров классов для работы с компилятором-интерпретатором. Этим мы и займемся далее. Для удобства я предлагаю сделать наше приложение консольным и оперировать в нем. Объявим набор экземпляров и рассмотрим,за что каждый из них отвечает:
здесь поле setup - это просто класс,хранящий в себе набор автоматически генерируемых настроек. Они будут применены при создании объекта runtime. Этот объект следует рассмотреть более подробно. Абстрактно-объект runtime содержит некие параметры той среды, где он будет работать и выполнять свой код (набор различных настроек и параметров). Ему необходимо передать в качестве сборки (assembly) то приложение, которое работает в данный момент (для людей,знакомых с рефлексией,это откроет безграничный простор для фантазии-с динамическими генерируемыми сборками развернутся есть куда). После этого мы создаем центр и сердце нашего интерпретатора - движок (engine). Именно он будет выполнять весь наш код. После его создания (как было оговорено выше,в качестве параметров передается исполняющая среда(runtime)). Остается только создать объект scope - именно он в будущем будет передаваться в качестве параметра в метод,отвкчающий за компиляцию. Зачем он нужен? На бытовом уровне к нему можно отнестись, как к некой связи компилируемого кода с нашей исходной программой, написанной на C#. scope - мост между кодом на Python и программой на C#.
После всех предварительных подготовок реализуем некоторое весьма простое ядро запуска кода:
while (true)
{
string script = Console.ReadLine();
try
{
engine.Execute(script, scope);
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
}
В этом коде даже реализована некая поддержка обработки исключений и вывода текста ошибки,что может оказаться весьма полезно. Здесь все тривиально. Считываем строчку, запускаем метод Execute, в который передаем строчку с кодом и scope - связь между программой на Python и кодом на C#. Добавляйте всякие украшательства и получите некую программу, которую написал я:
тут и обработка исключения компилятора и работоспособный код,который успешно выполнился.
На этом пока все. В следующих статьях мы рассмотрим немного синтаксиса языка Python, прикладное применение для решения конкретных задач, а также некие базовые возможности, которые могут понадобится.
До встречи и удачи вам в нелегком труде!
В современных достаточно объемных программах статический скомпилированный код может оказаться недостаточно гибок для решения какой либо задачи, ведь статичность-это всегда статичность,никого вмешательства, только мертвый двоичный код, неизменный после компиляции программы. Расшатать его, внести нечто новое иное - вот что действительно вызывает интерес у программистов в наше время. Представьте себе - налету программа сама генерирует себя, вносит в себя всевозможные изменения и приобретает новые свойства!
Быть может, не все пока еще осознают преимущество данной концепции) Давайте рассмотрим пример программы, задача реализации которой может встать перед программистом.
Задача: В зависимости от каких либо внешних источников создать несколько экземпляров класса, записать данные и потом пользоваться ими.
Пояснение: То есть необходимо где то прочитать набор инструкций и поступить в соответствии с ними.
Пример простой реализации: Давайте разберем небольшой пример кода,как можно сделать решить данную задачу.
У нас есть файл,содержащий набор строк следующего вида
Бони,23,181,56778908
Игги,57,170,55432330
Заранее мы знаем,что здесь идет перечисление характеристик. Не представляется сложным счесть строки из файла в массив строк и обработать каждую строку (разбить на части по запятым, и каждую лексему записать как значение соответствующей переменной).
string[] fileStrings = File.ReadAllLines("data.txt"); // data.txt - наш файл с двумя строками
Person[] person = new Person[fileStrings.Lenght]; //создаем массив экземпляров класса Person
for(int i = 0; i < fileStrings.Lenght; i++)
{
string[] tokens = fileStrings[i].Split(new char[]{','}); // получаем массив лексем
person[i] = new Person(); // создаем экземпляр
person[i].Name = tokens[0]; // забиваем каждое поле нашим токеном, предварительно //конвертируя его в нужный тип(приводя к нужному типу)
person[i].Age = int.Parse(tokens[1]);
person[i].Tall = int.Parse(tokens[2]);
person[i].Number = int.Parse(tokens[3]);
}Как вы могли бы заметить, данный способ очень тривиальный, но не совсем гибкий. Достаточно поменять местами записи в файле и весь алгоритм собьется. Бедному Игги будет 170 лет,а то еще и 55432330 =)
Конечно, все в основном будут смотреть в сторону XML,что и правильно. Там все четко, параметры и привязанные к ним значения. Если параметров 100 - писать будете код долго,нудно и не интересно.Хочется гибкости. Динамичности. Как если бы на лету компилировалась программа,опираясь на внешние источники в виде текстовых файлов.....)
Конечно, пример,приведенный выше-не самый яркий пример острой потребности в "динамическом коде", но такая проблема тоже может встать и при помощи этого метода вполне просто решится)
Динамический код нужен тогда,когда хорошо бы было на лету сгенерировать классы, не обращаясь к рефлексии, создать динамически экземпляры классов с именами,которых нет в коде исходной программы вообще, выполнить какие нибудь инструкции, которые человек захочет поменять (а двоичный код программы поменять невозможно). Вот тогда то и мы подходим вплотную в нашему вопросу.
Встроенный интерпретатор, способный напрямую взаимодействовать с объектами кода C#. Свой язык программирования в вашей программе. Продвинутый редактор скриптов в движке игры. Динамический компилируемый исполняемый код, тесно взаимодействующий с вашей программой, ее полями, методами, классами, пространствами имен. Все это-концепция динамического кода.
В наше время есть множество наработок, связанных с различными встраиваемыми языками программирования. Я хочу рассмотреть наиболее приглянувшийся и развивающийся комплекс модулей под названием IronPython. IronPython - динамически компилируемый код, взаимодействующий с CLR, работающий в среде .NET Framework и способный к полному взаимодействию с ней. По сути-вариация языка Python, любимого веб-программистами.
Более подробно с его описанием можно ознакомится на официальном сайте http://ironpython.net/
Там же есть и официальная документация на английском языке.
Для работы с ним нам понадобится скачать исходники IronPython и взять необходимые нам dll.
Исходники находятся здесь http://ironpython.codeplex.com/releases/view/54498#DownloadId=216705 (если вы используете Visual Studio 2008, то вам нужна более старая версия,а именно http://ironpython.codeplex.com/releases/view/12482#DownloadId=96607 )
После скачивания и распаковки в корневом каталоге будут содержаться все необходимые нам модули
IronPython.dll
IronPython.Modules.dll
Microsoft.Scripting.dll
Microsoft.Scripting.Debugging.dll
Их будет необходимо добавить в наш проект ( Project-Add Reference...)
Далее необходимо внести в директивы using использование соответствующих пространств имен
using Microsoft.Scripting.Hosting;
Предварительно мы подготовили почву для работы. Далее необходимо будет объявить несколько экземпляров классов для работы с компилятором-интерпретатором. Этим мы и займемся далее. Для удобства я предлагаю сделать наше приложение консольным и оперировать в нем. Объявим набор экземпляров и рассмотрим,за что каждый из них отвечает:
ScriptRuntimeSetup setup = Python.CreateRuntimeSetup(null);
ScriptRuntime runtime = new ScriptRuntime(setup);
runtime.LoadAssembly(System.Reflection.Assembly.GetExecutingAssembly());
ScriptEngine engine = Python.GetEngine(runtime);
ScriptScope scope = engine.CreateScope();здесь поле setup - это просто класс,хранящий в себе набор автоматически генерируемых настроек. Они будут применены при создании объекта runtime. Этот объект следует рассмотреть более подробно. Абстрактно-объект runtime содержит некие параметры той среды, где он будет работать и выполнять свой код (набор различных настроек и параметров). Ему необходимо передать в качестве сборки (assembly) то приложение, которое работает в данный момент (для людей,знакомых с рефлексией,это откроет безграничный простор для фантазии-с динамическими генерируемыми сборками развернутся есть куда). После этого мы создаем центр и сердце нашего интерпретатора - движок (engine). Именно он будет выполнять весь наш код. После его создания (как было оговорено выше,в качестве параметров передается исполняющая среда(runtime)). Остается только создать объект scope - именно он в будущем будет передаваться в качестве параметра в метод,отвкчающий за компиляцию. Зачем он нужен? На бытовом уровне к нему можно отнестись, как к некой связи компилируемого кода с нашей исходной программой, написанной на C#. scope - мост между кодом на Python и программой на C#.
После всех предварительных подготовок реализуем некоторое весьма простое ядро запуска кода:
while (true)
{
string script = Console.ReadLine();
try
{
engine.Execute(script, scope);
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
}
В этом коде даже реализована некая поддержка обработки исключений и вывода текста ошибки,что может оказаться весьма полезно. Здесь все тривиально. Считываем строчку, запускаем метод Execute, в который передаем строчку с кодом и scope - связь между программой на Python и кодом на C#. Добавляйте всякие украшательства и получите некую программу, которую написал я:
тут и обработка исключения компилятора и работоспособный код,который успешно выполнился.
На этом пока все. В следующих статьях мы рассмотрим немного синтаксиса языка Python, прикладное применение для решения конкретных задач, а также некие базовые возможности, которые могут понадобится.
До встречи и удачи вам в нелегком труде!
Комментариев нет:
Отправить комментарий