Compartilhar via


Usando representantes de atividades

Os representantes de atividade permitem autores de atividade para expor retornos de chamada com assinaturas específicas, para que os usuários de atividade podem fornecer manipuladores atividades base. Dois tipos de representantes de atividade estão disponíveis: ActivityAction<T> é usado para definir os representantes de atividade que não têm um valor de retorno, e ActivityFunc<TResult> é usado para definir os representantes de atividade que têm um valor de retorno.

Os representantes de atividade são úteis em situações onde uma atividade filho deve ser restrita a ter uma determinada assinatura. Por exemplo, uma atividade de While pode conter qualquer tipo de atividade filho sem restrições, mas o corpo de uma atividade de ForEach<T> é ActivityAction<T>, e a atividade filho que é executada por finalmente ForEach<T> deve ter InArgument<T> que é o mesmo tipo dos membros da coleção que ForEach<T> enumera.

Usando ActivityAction

Várias atividades do .NET Framework 4.6.1 usam ações de atividade, como a atividade de Catch e a atividade de ForEach<T>. Em cada caso, a ação de atividade representa um local onde o autor de fluxo de trabalho especifica uma atividade para fornecer um comportamento desejado quando estiver compondo um fluxo de trabalho usando uma dessas atividades. No exemplo a seguir, uma atividade de ForEach<T> é usada para exibir texto na janela do console. O corpo de ForEach<T> é especificado usando ActivityAction<T> que corresponde ao tipo de ForEach<T> que é cadeia de caracteres. A atividade de WriteLine especificada em Handler tem seu argumento de Text associado a valores de cadeia de caracteres na coleção que a atividade de ForEach<T> itera.

DelegateInArgument<string> actionArgument = new DelegateInArgument<string>();

Activity wf = new ForEach<string>
{
    Body = new ActivityAction<string>
    {
        Argument = actionArgument,
        Handler = new WriteLine
        {
            Text = new InArgument<string>(actionArgument)
        }
    }
};

List<string> items = new List<string>();
items.Add("Hello");
items.Add("World.");

Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Values", items);

WorkflowInvoker.Invoke(wf, inputs);

O actionArgument é usado para fluir itens individuais na coleção para WriteLine. Quando o fluxo de trabalho é chamado, a saída a seguir são exibidas no console.

HelloWorld.

Os exemplos deste tópico usam sintaxe de inicialização de objeto. A sintaxe de inicialização de objeto pode ser uma maneira útil de criar definições de fluxo de trabalho no código porque fornece uma exibição hierárquica das atividades no fluxo de trabalho e mostra a relação entre as atividades. Não há nenhum requisito para usar a sintaxe de inicialização de objeto quando você cria fluxos de trabalho programaticamente. O exemplo a seguir é funcionalmente equivalente ao exemplo anterior.

DelegateInArgument<string> actionArgument = new DelegateInArgument<string>();

WriteLine output = new WriteLine();
output.Text = new InArgument<string>(actionArgument);

ActivityAction<string> body = new ActivityAction<string>();
body.Argument = actionArgument;
body.Handler = output;

ForEach<string> wf = new ForEach<string>();
wf.Body = body;

List<string> items = new List<string>();
items.Add("Hello");
items.Add("World.");

Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Values", items);

WorkflowInvoker.Invoke(wf, inputs);

Para obter mais informações sobre os inicializadores do objeto, consulte Como inicializar objetos sem chamar um construtor (Guia de programação em C#) e Como declarar um objeto usando um inicializador de objeto (Visual Basic).

No exemplo a seguir, uma atividade de TryCatch é usada em um fluxo de trabalho. ApplicationException é gerada pelo fluxo de trabalho, e tratado por uma atividade de Catch<TException> . O identificador para a ação de atividade da atividade Catch<TException> é uma atividade WriteLine e o detalhe de exceção flui por ela por meio de ex DelegateInArgument<T>.

DelegateInArgument<ApplicationException> ex = new DelegateInArgument<ApplicationException>()
{
    Name = "ex"
};

Activity wf = new TryCatch
{
    Try = new Throw()
    {
        Exception = new InArgument<Exception>((env) => new ApplicationException("An ApplicationException was thrown."))
    },
    Catches =
    {
        new Catch<ApplicationException>
        {
            Action = new ActivityAction<ApplicationException>
            {
                Argument = ex,
                Handler = new WriteLine()
                {
                    Text = new InArgument<string>((env) => ex.Get(env).Message)
                }
            }
        }
    },
    Finally = new WriteLine()
    {
        Text = "Executing in Finally."
    }
};

Ao criar uma atividade personalizado que define ActivityAction<T>, use InvokeAction<T> para modelar invocação do ActivityAction<T>. Nesse exemplo, uma atividade de WriteLineWithNotification personalizado é definida. Esta atividade é composta de Sequence que contém uma atividade de WriteLine seguida por InvokeAction<T> que invoca ActivityAction<T> que recebe um argumento de cadeia de caracteres.

public class WriteLineWithNotification : Activity
{
    public InArgument<string> Text { get; set; }
    public ActivityAction<string> TextProcessedAction { get; set; }

    public WriteLineWithNotification()
    {
        this.Implementation = () => new Sequence
        {
            Activities =
            {
                new WriteLine
                {
                    Text = new InArgument<string>((env) => Text.Get(env))
                },
                new InvokeAction<string>
                {
                    Action = TextProcessedAction,
                    Argument = new InArgument<string>((env) => Text.Get(env))
                }
            }
        };
    }
}

Quando um fluxo de trabalho é criado usando a atividade de WriteLineWithNotification , o autor de fluxo de trabalho especifica a lógica personalizada desejada em Handlerde ação de atividade. Nesse exemplo, um fluxo de trabalho é criado usando a atividade de WriteLineWithNotification , e uma atividade de WriteLine é usada como Handler.

// Create and invoke the workflow without specifying any activity action
// for TextProcessed.
Activity wf = new WriteLineWithNotification
{
    Text = "Hello World."
};

WorkflowInvoker.Invoke(wf);

// Output:
// Hello World.

// Create and Invoke the workflow with specifying an activity action
// for TextProcessed.
DelegateInArgument<string> msg = new DelegateInArgument<string>();
Activity wf2 = new WriteLineWithNotification
{
    Text = "Hello World with activity action.",
    TextProcessedAction = new ActivityAction<string>
    {
        Argument = msg,
        Handler = new WriteLine
        {
            Text = new InArgument<string>((env) => "Handler of: " + msg.Get(env))
        }
    }
};

// Invoke the workflow with an activity action specified
WorkflowInvoker.Invoke(wf2);

// Output:
// Hello World with activity action.
// Handler of: Hello World with activity action.

Há várias versões genéricas de InvokeAction<T> e de ActivityAction<T> fornecidos passando um ou mais argumentos.

Usando ActivityFunc

ActivityAction<T> é útil quando não há nenhum valor do resultado da atividade, e ActivityFunc<TResult> é usado quando um valor de resultado é retornado. Ao criar uma atividade personalizado que define ActivityFunc<TResult>, use InvokeFunc<TResult> para modelar invocação do ActivityFunc<TResult>. No exemplo a seguir, uma atividade de WriteFillerText é definida. Para fornecer o texto de preencher, InvokeFunc<TResult> é especificado que recebe um argumento integer e tem um resultado de cadeia de caracteres. Uma vez que o texto do enchimento é recuperado, é exibido no console usando uma atividade de WriteLine .

public class WriteFillerText : Activity
{
    public ActivityFunc<int, string> GetText { get; set; }
    public InArgument<int> Quantity { get; set; }

    Variable<string> text = new Variable<string>
    {
        Name = "Text"
    };

    public WriteFillerText()
    {
        this.Implementation = () => new Sequence
        {
            Variables =
            {
                text
            },
            Activities =
            {
                new InvokeFunc<int, string>
                {
                    Func = GetText,
                    Argument = new InArgument<int>((env) => Quantity.Get(env)),
                    Result = new OutArgument<string>(text)
                },
                new WriteLine
                {
                    Text = new InArgument<string>(text)
                }
            }
        };
    }
}

Para fornecer texto, uma atividade deve ser usada que recebe um argumento de int e tem um resultado de cadeia de caracteres. Este exemplo mostra uma atividade de TextGenerator que atenda a esses requisitos.

public class TextGenerator : CodeActivity<string>
{
    public InArgument<int> Quantity { get; set; }
    public InArgument<string> Text { get; set; }

    protected override string Execute(CodeActivityContext context)
    {
        // Provide a quantity of Random Text
        int q = Quantity.Get(context);
        if (q < 1)
        {
            q = 1;
        }

        string text = Text.Get(context) + " ";
        StringBuilder sb = new StringBuilder(text.Length * q);
        for (int i = 0; i < q; i++)
        {
            sb.Append(text);
        }

        return sb.ToString();
    }
}

Para usar a atividade de TextGenerator com a atividade de WriteFillerText , especifique-o como Handler.

DelegateInArgument<int> actionArgument = new DelegateInArgument<int>();

Activity wf = new WriteFillerText
{
    Quantity = 5,
    GetText = new ActivityFunc<int, string>
    {
        Argument = actionArgument,
        Handler = new TextGenerator
        {
            Quantity = new InArgument<int>(actionArgument),
            Text = "Hello World."
        }
    }
};

WorkflowInvoker.Invoke(wf);