Lua и C/C++/C#. Часть 2

Вообще, использование Lua для платформы .NET сейчас часто воспринимается как специфическое отклонение. Это и так, и не так одновременно, учитывая то, что .NET постоянно расширяется.

В прошлой части мы продемонстрировали два очень простых примера, в результате которых читатели могли узнать о том, как управлять функциями C# из Lua-сценариев. Также мы затронули довольно весомую тему CLR (Common Language Runtime — общеязыковой исполняющей среды платформы .NET), CTS (Common Type System — общей системы типов) и CLS (Common Languages Specification — общеязыковой спецификации). Если говорить простыми словами, то под всем этим подразумевается успешная попытка Microsoft тотального объединения множества смежных языков в рамках единой платформы .NET, о которой хорошо наслышаны программисты различных рангов. Семейства языков Microsoft Visual Studio (MSVS) в последних версиях отличаются больше синтаксисом, чем функциональностью. Написанный на них код преобразуется в CIL-инструкции (CIL — общий промежуточный язык, Common Intermediate Language), которые в свою очередь компилируются оперативным (JIT — just-in-time) компилятором. Например, в C# конкатенация строк обозначается знаком «+», в VB.NET она же — амперсандом «&». Но при всей этой разнице соответствующие .NET-компиляторы, а именно, csc.exe и vbc.exe скомпилируют схожий набор CIL-инструкций. Это, по существу, и есть основной смысл общеязыковой спецификации CLS.

Нужно сказать, что используемая нами в примерах библиотека LuaInterface.dll сейчас имеет прямое отношение непосредственно к .NET, потому как отвечает большей частью за трансляцию кода Lua и конвертацию данных в рамках сред или языков программирования, поддерживающих общеязыковую исполняющую среду CLR. Библиотека написана большей частью на C#, хотя в ней имеется и около 30 строчек на обычном С.

Конечно, на самом деле, функционально языки все-таки отличаются и в некоторых моментах довольно сильно, но сейчас идет вариант общего смешения. При этом нужно отметить, что основные типы для большинства языков программирования определены в рамках CTS и преобразование идет с соответствующей привязкой. Классы, перечисления, структуры — все это относится к CTS.

Самым неуклюжим моментом в данной ситуации является то, что основной язык для платформы .NET, коим по праву можно считать C#, периодически изменяется, поэтому примеры-листинги в рамках многих опубликованных в книгах и на интернет-сайтах уроков часто являются устаревшими. Так что все время сверяйте версии. Наше повествование строится на базе VC# 2008 и Lua 5.1 (который также довольно сильно отличается от 5.0).

Задание для примера №3

Допустим, у нас есть учебная группа. Нужно: в C# дать определения основным классам и методам, а в рамках Lua-сценариев написать код для создания и загрузки списка студентов, включающего их имена и краткие характеристики.

Что требуется изначально?

По аналогии с прошлыми примерами нам, естественно, понадобится Visual C# либо сразу MSVS. Если в том архиве LuaInterface, который мы использовали раньше, не имеется библиотеки luanet.dll (у меня, например, ее не было), дополнительно скачайте полный дистрибутив LuaForWindows_v5.1.4-45.exe c www.lua.org и установите его. Там luanet.dll будет находиться в папке clib. Конечно, можно бы было заняться и самостоятельной сборкой, но для этого урока такое отклонение будет излишним, потому как начинающему специалисту нужно прочувствовать, что же может Lua в рамках интеграции.

Теперь запускаем VC# и создаем новый проект (Console Application), назовем его LuaTest03. В Reference добавляем библиотеку LuaInterface.dll, а также в папку …\LuaTest03\bin\Debug копируем luanet.dll.

В заголовке нашего основного cs-файла прописываем следующее:

using System;
using System.Collections.Generic;
using LuaInterface;

С System и LuaInterface в данном случае все понятно — мы с ними уже работали, а System.Collections.Generic нам понадобится для использования обобщенных типов классов, реализующих перечисления.

Теперь приступим к написанию кода.

Пишем на С#

Итак, в рамках приложения нам предстоит создать два собственных класса — для студента и для группы.
Для начала определим класс для студента, в пространство имен LuaTest03 вписываем следующие строки:

class Student
{
public string Description = "";
public string Name = "";
public void GiveName(string name)
{
Name = name;
}
}

Как видите, мы подразумеваем обычную структуру с двумя свойствами (имя Name и описание Description) и одним методом GiveName(). Такое разделение нам нужно для более подробного рассмотрения интеграции сценариев и компилируемой части.

Второй класс я для удобства и скорости переименовал из Program, название которого генерируется по умолчанию при старте нового проекта, в Group. Теперь нам нужно создать перечисление, за основу которого возьмем вариант List из System.Collections.Generic, а также функции просмотра всего списка и добавления в список. Поэтому в класс Group вводим следующие строки кода:

List students = new List();
public void Look()
{
foreach (Student s in students)
{
Console.WriteLine(s.Name + ": " + s.Description);
}
}
public void AddStudentToGroup(Student s)
{
students.Add(s);
}

Итак, первая строка из добавленных — это непосредственно создание нового списка. Функция Look() осуществляет просмотр его содержимого, а AddStudentToGroup() осуществляет добавление новой записи за счет использования метода add(), имеющегося в стандартном наборе для List. Как видите, все очень просто.

Теперь самое время запускать Lua, поэтому ниже добавляем следующие строки:

Lua lua = new Lua();
public Lua Lua
{
get { return lua; }
}
public Group()
{
lua.RegisterFunction("JoinGroup", this,
GetType().GetMethod("AddStudentToGroup"));
}

В принципе, и здесь вы не увидите ничего особенного: мы запускаем интерпретатор Lua, а с помощью метода RegisterFunction() получаем доступ через Lua к C#-функции AddStudentToGroup, и в рамках Lua-кода она будет называться JoinGroup.

Теперь осталось заполнить ключевую функцию Main(), хотя торопиться в данном случае не будем, и перейдем к созданию Lua-сценария.

Программируем на Lua

Итак, в папке …\LuaTest03\bin\Debug создаем новый каталог scripts, в котором опять же создаем текстовый файл, назвав его students.txt. В него помещаем такой код:

luanet.load_assembly ("LuaTest03")
Student = luanet.import_type ("LuaTest03.Student")
-- Михаил Иванов
mike_iv = Student()
mike_iv.Description = "Старательный студент"
mike_iv:GiveName("Михаил Иванов")
JoinGroup(mike_iv)
-- Стефания Ульянова
step_ul = Student()
step_ul.Description = "Талантливый ученый"
step_ul:GiveName("Стефания Ульянова")
JoinGroup(step_ul)

В данном случае мы используем библиотеку luanet.dll, при этом метод load_assembly загружает некое конкретное пространство имен, а import_type, как ясно из названия, импортирует определенный в этом пространстве тип. В нашем случае мы получили доступ к классу Student, и теперь нам доступно его полноценное использование. Далее мы создаем первый экземпляр класса для Михаила Иванова, вписываем характеристику для него и, внимание (!), вызываем метод, который добавляет имя. Причем, как вы можете заметить, свойство записывается после точки, а метод — после двоеточия.

Конечно, имя мы могли бы вписывать, как и характеристику, но в данном случае просто демонстрируется возможность использования методов, определенных в рамках класса. После произведенных действий строкой JoinGroup(mike_iv) мы помещаем студента Иванова в список Students основной программы.

Далее для массовости добавим еще одного студента — Стефанию Ульянову.

Функция Main()

Итак, для функции Main() ничего особенно сложного писать не требуется, нам нужно просто запустить на выполнение Lua-сценарий, после чего посмотреть загруженный список студентов. Таким образом, все у нас будет выглядеть так:

static void Main(string[] args)
{
Group group = new Group();
group.Lua.DoFile("scripts/students.txt");
group.Look();
Console.WriteLine("Нажмите Enter для выхода.");
Console.ReadLine();
}

Как видите, мы создаем экземпляр класса Group, после чего в его рамках вызываем файл со сценарием на исполнение, а после просматриваем загруженный список.


Подытоживая пример №3

Таким образом, вы увидели, как можно работать с классами, определенными в рамках C#-кода, из внешних источников. Причем, выходя на глобальные и используемые средой пространства имен типа System.Windows.Forms или System.Drawing, вы фактически можете программировать буквально все прямо из Lua-файлов, а именно, вызывать любые типы и методы.

Пока все может показаться очень простым. На самом деле, в использовании Lua не так и много сложных моментов, хотя язык сейчас начинает охватывать все большее количество сфер. Самое главное — это грамотное отделение компилируемой части от сценариев.

Отдельно стоит сказать, что сейчас мы рассматриваем примеры использования Lua в рамках платформы .NET, где все делается несколько специфично по сравнению с другими вариантами. Вместе с тем .NET уже распространилась на множество других языков, полный список которых можно увидеть на сайте http://dotnetlanguages.net. Здесь вы убедитесь, что таких языков много, а .NET работает не только в Windows, но и в других распространенных операционных системах. Поэтому ставка разработчиков Lua, которые от версии к версии сближали LuaInterface с .NET-платформой, вполне объяснима. В следующей части мы сделаем простейший игровой пример с созданием NPC.

Кристофер http://itcs.3dn.ru


Компьютерная газета. Статья была опубликована в номере 34 за 2011 год в рубрике программирование

©1997-2024 Компьютерная газета