Поделиться через


Не универсальный "ForEach"

.NET Framework 4.6.1 поставляется с набором действий управления потоком на панели элементов, включая ForEach<T>, который позволяет выполнять итерации по коллекциям IEnumerable<T>.

ForEach<T> требует, чтобы его Values свойство было типом IEnumerable<T>. Это предотвращает итерацию пользователей над структурами данных, реализующими IEnumerable<T> интерфейс (например, ArrayList). Необобщённая версия ForEach<T> преодолевает это требование, повышая сложность на уровне среды выполнения для обеспечения совместимости типов значений в коллекции.

В примере NonGenericForEach показано, как реализовать не универсальное ForEach<T> действие и его конструктор. Это действие можно использовать для итерации ArrayList.

Операция ForEach

Инструкция C#/Visual Basic foreach перечисляет элементы коллекции, выполняя внедренную инструкцию для каждого элемента коллекции. Эквивалентные действия foreach в WF — это ForEach<T> и ParallelForEach<T>. Действие ForEach<T> содержит список значений и текст. Во время выполнения список итерируется, и тело выполняется для каждого значения в списке.

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

Определение класса

В следующем примере кода показано определение не универсального ForEach действия.

[ContentProperty("Body")]
public class ForEach : NativeActivity
{
    [RequiredArgument]
    [DefaultValue(null)]
    InArgument<IEnumerable> Values { get; set; }

    [DefaultValue(null)]
    [DependsOn("Values")]
    ActivityAction<object> Body { get; set; }
}

Содержание (необязательно) выполняется для каждого элемента в коллекции и имеет тип ActivityActionObject. Каждый отдельный элемент передается в Body через его Argument свойство.

Значения (необязательно) Коллекция элементов, которые итерируются. Обеспечение того, чтобы все элементы коллекции были совместимыми типами во время выполнения.

Пример использования forEach

В следующем коде показано, как использовать действие ForEach в приложении.

string[] names = { "bill", "steve", "ray" };

DelegateInArgument<object> iterationVariable = new DelegateInArgument<object>() { Name = "iterationVariable" };

Activity sampleUsage =
    new ForEach
    {
       Values = new InArgument<IEnumerable>(c=> names),
       Body = new ActivityAction<object>
       {
           Argument = iterationVariable,
           Handler = new WriteLine
           {
               Text = new InArgument<string>(env => string.Format("Hello {0}",                                                               iterationVariable.Get(env)))
           }
       }
   };
Состояние Сообщение Степень серьезности Тип исключения
Значения: null Значение для обязательного аргумента действия 'Значение' не было предоставлено. Ошибка InvalidOperationException

Конструктор «forEach»

Конструктор действий в примере по внешнему виду похож на конструктор, предоставленный для встроенного ForEach<T> действия. Конструктор отображается на панели элементов в категории «Примеры», «Неуниверсальные действия». Конструктор называется ForEachWithBodyFactory на панели элементов, потому что это действие предоставляет IActivityTemplateFactory, который создает действие с правильно настроенным ActivityAction.

public sealed class ForEachWithBodyFactory : IActivityTemplateFactory
{
    public Activity Create(DependencyObject target)
    {
        return new Microsoft.Samples.Activities.Statements.ForEach()
        {
            Body = new ActivityAction<object>()
            {
                Argument = new DelegateInArgument<object>()
                {
                    Name = "item"
                }
            }
        };
    }
}

Чтобы запустить этот пример

  1. Задайте проект вашего выбора в качестве начального проекта решения:

    1. CodeTestClient показывает, как использовать действие с помощью кода.

    2. DesignerTestClient показывает, как использовать активность в конструкторе.

  2. Соберите проект и запустите его.