Переменные

Зачем?

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

В EyeAuras целая россыпь различных вариантов хранения данных. Пройдемся от самых короткоживущих, до самых долговременных

Примеры ниже выполняются в C# Script работающего EyeAuras. Variables, AuraTree и Log предоставляет хост. Обычному C# классу соответствующие сервисы нужно передать явно.

Локальные переменные

Тут ничего сложного - эти переменные живут ровно пока метод/блок кода не завершился. Здесь никаких особенностей.

var test = 123;

Свойства песочницы

Так как скрипт ваш является классом из языка C#, то никто не мешает объявлять свойства и назначать им значения. Значения этих свойств сохраняются между запусками одного экземпляра песочницы. После изменения кода и перекомпиляции, а также при другом пересоздании песочницы, значения теряются. Это удобно для вещей, которые нужно инициализировать один раз на время её жизни; запись на диск такой код не выполняет.

csharp

int MyCounter { get; set; }

// здесь много-много вашего кода

MyCounter = 16;

// здесь еще больше кода

Log.Info($"Counter: {MyCounter}");

Переменные скриптов/аур/папок

А вот здесь уже начинаются нестандартные вещи, являющиеся частью архитектуры EyeAuras. Для хранения вне локального запуска скрипта можно сохранять данные в аурах, папках и деревьях. Для того, чтобы просмотреть текущие значения переменных нужно выбрать ауру или папку и открыть закладку Variables. Там видно тип, текущее значение, когда обновлялась и т.п. Редактировать пока возможности нет, только удалить. Основное назначение такого тип переменных это передача данных от одного скрипта к другому, храниение пользовательской конфигурации и т.п.

Переменные скриптов - Variables API

У скрипта есть возможность читать и писать переменные владельца, которые сохраняются при изменении кода скрипта. Другие скрипты могут обратиться к ним, если явно выберут того же владельца. Variables без пути использует текущий контекст: одинаковое имя в двух разных скриптах ещё не означает общее хранилище. К примеру, один ваш скрипт может отвечать за конфигурацию, а второй - уже выполнять работу, используя ее.

Итак, ваши скрипты, которые запускается в песочнице, по умолчанию имеют доступ к свойству Variables

Log.Info($"Variables count: {Variables.Count}");

Там довольно много всяких методов, но мы обратим внимание на два основных способа. Это ассоциативный массив, т.е. мы можем туда писать и читать, используя строки.

Для начала, давайте туда что-нибудь запишем.

csharp
Variables["myCounter"] = 1; // записываем 1 в переменную с именем myCounter
Log.Info($"Counter value: {Variables["myCounter"]}"); // считываем значение переменной myCounter, будет 1

Минус данного подхода в том, что если нам нужно понимать с каким типом данных мы работаем, то нужно выполнять кастинг к нужному типу, потому что индексатор возвращает object, даже если внутри хранится int.

csharp
Variables["myCounter"] = 1; // записываем 1 в переменную с именем myCounter
// Variables["myCounter"] = Variables["myCounter"] + 1; // не сработает и выдаст ошибку!

Variables["myCounter"] = (int)Variables["myCounter"] + 1; // а вот это уже сработает
Log.Info($"Counter value: {Variables["myCounter"]}"); // в myCounter будет 2

C# это не Python, ему важно знать типы данных, с которыми язык работает. Однако постоянно выполнять кастинг к нужному типу очень неудобно и здесь на помощь приходит вспомогательный класс ScriptVariable<T>, который позволяет единожды указать имя и тип переменной, а дальше работать с ними напрямую.

csharp
var myCounter = Variables.Get<int>("myCounter"); // инициализируем переменную типа int с именем myCounter
myCounter.Value = myCounter.Value + 1; // увеличиваем значение на 1
Log.Info($"Counter value: {myCounter.Value}"); // в myCounter будет 2, 3 и т.п.

В таком варианте нужно всего один раз объявить переменную, практически как с локальными, а дальше работать с ними не особо беспокоясь о том, что где-нибудь вы перепутаете имя или тип.

Переменные аур/папок

Ровно точно так же как и скрипт, каждая аура и каждая папка является в том числе контейнером для хранения любых переменных. Зная путь к ауре/папке, можно получить доступ к ее переменным. У Variables есть два метода ScriptVariable<T> Get<T>(string auraPath, string variableName); и ScriptVariable<T> Get<T>(IHasVariables source, string variableName);, используя которые можно читать и писать переменные любого источника

Вариант номер 1

csharp
// Создайте рядом со скриптом ауру Something.
var auraVariable = Variables.Get<int>(@".\Something", "myCounter");
auraVariable.Value = 16;

Указываем где искать ауру/папку/дерево, дальше программа все сделает сама

Вариант номер 2 — через найденную ауру

csharp
var aura = AuraTree.GetAuraByPath(@".\Something");
var auraVariable = Variables.Get<int>(aura, "myCounter");
auraVariable.Value = 16;

Находим сначала ауру/папку и дальше указываем, что читать переменные нужно из нее.

Иерархия

Все переменные аур и папок соблюдают иерархию, т.е. если вы вписали какое-то значение в переменную на уровне папки, то у всех дочерних папок и аур будет возможность прочитать это значение. При этом поддерживается возможность оверрайдить значение. Наиболее близким аналогом этой структуры является CSS из HTML. Такая структура позволяет очень гибко передавать настройки всем дочерним аурам. EyeAuras использует эту особенность для передачи дефолтных значений вглубь дерева, таких как окно, к которому нужно цепляться, симулятор, который использовать для ввода и т.п. p.s. Перезаписав, к примеру, default.WindowSelector.TargetWindow вы тем самым повлияете на то, каким будет выбрано дефолтное окно во всех вложенных аурах

Blackboard aka переменные деревьев

TBA

Для различения отсутствующей записи, null и значения по умолчанию, а также подписки на изменения смотрите операции с типизированными переменными. Сам дескриптор не является гарантией сохранения произвольного объекта на диск.

Законченный пример наследования, возврат к значению папки после Remove() и сравнение состояния между повторными Run — в руководстве по владельцам и времени жизни.