Перебор переменных

<< Click to Display Table of Contents >>

Navigation:  Проект > Элементы дерева объектов > Палитра ФБ > Служебные > Скрипт > Руководство и примеры > Обращение к переменным проекта >

Перебор переменных

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

Например, сделаем пример, в котором все значения объекта в котором находится скрипт, а также вложенных записались бы в CSV файл. Подготовим набор значений

sluzhebnie_skript_rukovodstvo_i_primery_obrashchenie_k_peremennym_proekta_perebor_peremennyh

Добавим скрипт, в него добавим два входа - Записать и ПутьФайла, а также выход Ошибка.

sluzhebnie_skript_rukovodstvo_i_primery_obrashchenie_k_peremennym_proekta_perebor_peremennyh1

Начнем с простого - нам необходимо чтобы код обработки переменных и записи в файл, обрабатывался по переднему фронту на входе Записать. Для этого можно применить следующую запись.

public partial class ФБ : ScriptBase
{
    bool? M = false;
    public override void Execute()
    {
        if (Записать == true && M == false)
        {
        }
        M = Записать;
    }
}

Переменная M объявлена вне метода Execute - в классе. В этом случае ее значение будет сохраняться между циклами. В условии мы проверяем, если переменная равна true и M==false, то мы вызовем код. Каждый цикл опроса M сохраняется.

Теперь разберемся с сохранением файла. Для этого можно использовать штатный функционал .Net - класс StreamWriter. Чтобы его использовать сначала нужно добавить его пространство имен:

using System.IO;

Воспользуемся перегруженным конструктором с тремя параметрами – именем файла, флагом перезаписи (false – перезапись файла, true – добавление новых данных в файл), и кодировка. При работе с неуправляемыми ресурсами - файлами, SQL соединениями и т.д. такой вызов следует обернуть в оператор using, в таком случае гарантируется очищение памяти после выполнения кода.

public partial class ФБ : ScriptBase
{
    bool? M = false;
    public override void Execute()
    {
        if (Записать == true && M == false)
        {
            using (var file = new StreamWriter(ПутьФайла, false, System.Text.Encoding.GetEncoding("windows-1251")))
            {
            }
        }
        M = Записать;
    }
}

Теперь нужно реализовать перебор переменных в MasterSCADA, для этого можно использовать метод NavigateChilds. В данный метод передается три параметра:

1.Делегат, вызываемый для каждого дочернего элемента. Делегат - это ссылка на вызываемый метод, который вызывается для каждого дочернего элемента (item), если делегат вернет false, перебор останавливается, если true - то происходит переход к следующему элементу.

2.Тип искомых элементов - входы, значения, расчеты, команды и т.д. В нашем случае мы будет искать

3.Флаги поиска определяющие пространство поиска переменных.

Код перебора переменных будет выглядеть следующим образом.

//перебор всех значений данного объекта
HostFB.TreeItemHlp.Parent.NavigateChilds(delegate (ITreeObjectHlp item)
{
 if (item.ObjectType != EObjectType.otValue)
  return true;
 ITreePinHlp command = (ITreePinHlp)item;
 string objValue = (command.GetRTPin().ObjectValue).ToString();
 file.WriteLine("{0};{1}", command.Name, objValue); //записываем в файл
 return true;
}, TreeItemMask.Pin, NavigateItemsFlags.CurrentComputer);

Рассмотрим код построчно.

В первой строке происходит вызов метода NavigateChilds, где первым параметром идет наш делегат и код в виде лямбда-функции. В первой строке лямбда-функции происходит проверка на тип значения переменной:

if (item.ObjectType != EObjectType.otValue)  
    return true;

Это необходимо сделать, поскольку вторым параметром нашего метода мы передали TreeItemMask.Pin, а в данном параметра возвращаются и значения и входы ФБ. Поэтому необходимо сделать дополнительную проверку, чтобы не обрабатывать входы.

Далее происходит получение значения, аналогично как на прошлом шаге. После чего, с помощью метода ToString() значение преобразуется в строку.

ITreePinHlp command = (ITreePinHlp)item;
string objValue = (command.GetRTPin().ObjectValue).ToString();

После того как значение сформировано, можно записать его и имя переменной в файл.

file.WriteLine("{0};{1}", command.Name,objValue); //записываем в файл

В конце:

}, TreeItemMask.Pin, NavigateItemsFlags.CurrentComputer);

находятся два оставшихся параметра метода NavigateChilds.

TreeItemMask.Pin – определяет среди каких элементов проекта нужно выполнять поиск. Pin – это элементы тип входа - «Значение» и «Вход». Можно также задать Pout (выходы, команды), Parser (Расчет), Event (Событие), FuncBlock (функциональный блок), All (все) и другие варианты.

NavigateItemsFlags.CurrentComputer – флаги, определяющие пространство поиска переменных, в данном случае – только на текущем компьютере.

Итоговый код скрипта выглядит так:

using System;
using MasterSCADA.Script.FB;
using MasterSCADA.Hlp;
using FB;
using FB.FBAttributes;
using System.Linq;
using System.IO;
using MasterSCADALib;
[FBRetain]
public partial class ФБ : ScriptBase
{
    bool? M = false;
 
    public override void Execute()
    {
        if (Записать == true && M == false)
        {
            using (var file = new StreamWriter(ПутьФайла, false, System.Text.Encoding.GetEncoding("windows-1251")))
            {
                //перебор всех значений данного объекта
                HostFB.TreeItemHlp.Parent.NavigateChilds(delegate (ITreeObjectHlp item)
                {
                    if (item.ObjectType != EObjectType.otValue)
                        return true;
                    ITreePinHlp command = (ITreePinHlp)item;
                    string objValue = (command.GetRTPin().ObjectValue).ToString();
                    file.WriteLine("{0};{1}", command.Name, objValue); //записываем в файл
                    return true;
                }, TreeItemMask.Pin, NavigateItemsFlags.CurrentComputer);
            }
        }
        M = Записать;
    }
}

Как адаптировать скрипт под свою задачу?

Сначала, нужно определится с поиском – где и переменные каких типов вы ищете. Если вы вызываете метод NavigateChilds у HostFB.TreeItemHlp.Parent, то вы выполняете поиск в объекте где находится скрипт и всех его подобъектов. Если нужно произвести поиск во всем проекте, то метод вызывается у HostFB.TreeItemHlp.Project. С помощью второго аргумента метода NavigateChilds вы определяете переменные какого типа вас интересуют (входы, выходы, расчеты или все переменные).

Затем нужно адаптировать код в лямбда-функции. Если нужно – вначале выполнить дополнительную проверку на тип возвращенной переменной, и, если она вам неинтересна, выполнить return true.

 

После преобразования переменной к типу ITreePinHlp, можно работать со значением, меткой времени и качеством. В нашем примере значение переменной преобразовывалось в строку. Если нужно получить конкретный тип, например, Double, то преобразование можно выполнить так:

double objValue = Convert.ToDouble(command.GetRTPin().ObjectValue);

Если нужно проверить переменную на определенный тип, то для этого нужно использовать оператор is. Например, если нас не интересуют переменные строкового типа нужно выполнить:

if (objValue is string) return true;

Теперь получив значения, вы можете оперировать с ними как вам требуется – выполнять математическую обработку, определять состояние определенных значений у переменных, экспортировать данные в СУБД и т.д.

По ссылке находится готовый проект. Проект немного дополнен - в него добавлен блок перехвата ошибок try-catch, который при обнаружении ошибок выведет сообщение в окно, а также проверяется существования папки сохранения, а в случае ее отсутствия - она создается автоматически.