Partager via


Utilisation de délégués d'activité

Les délégués d'activité permettent aux auteurs d'activités d'exposer des rappels avec des signatures spécifiques pour lesquelles les utilisateurs de l'activité peuvent fournir des gestionnaires basés sur l'activité. Deux types de délégués d'activité sont disponibles : ActivityAction<T> est utilisé pour définir des délégués d'activité qui n'ont pas de valeur de retour et ActivityFunc<TResult> est utilisé pour définir des délégués d'activité qui ont une valeur de retour.

Les délégués d'activité sont utiles dans les scénarios où une activité enfant doit être limitée à une certaine signature. Par exemple, une activité While peut contenir tout type d’activité enfant sans contraintes, mais le corps d’une activité ForEach<T> est un ActivityAction<T>, et l’activité enfant exécutée finalement par ForEach<T> doit avoir un InArgument<T> qui est du même type que les membres de la collection que le ForEach<T> énumère.

Utilisation d'ActivityAction

Plusieurs activités .NET Framework 4.6.1 utilisent des actions de l’activité, telles que l’activité Catch et l’activité ForEach<T>. Dans chaque cas, l'action de l'activité représente un emplacement où l'auteur de workflow spécifie une activité pour fournir le comportement voulu lors de la composition d'un workflow à l'aide de l'une de ces activités. Dans l'exemple suivant, une activité ForEach<T> est utilisée pour afficher un texte dans la fenêtre de console. Le corps du ForEach<T> est spécifié à l'aide d'un ActivityAction<T> qui correspond au type du ForEach<T> qui est le type chaîne. L’activité WriteLine spécifiée dans le Handler a son argument Text lié aux valeurs de chaîne dans la collection au sein de laquelle l’activité ForEach<T> itère.

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);

L'actionArgument est utilisé pour transférer les éléments individuels dans la collection au WriteLine. Lorsque le workflow est appelé, la sortie suivante s'affiche sur la console.

HelloWorld.

Les exemples de cette rubrique utilisent la syntaxe d'initialisation d'objet. La syntaxe d'initialisation d'objet peut être une méthode utile pour créer des définitions de workflow dans le code, car elle fournit une vue hiérarchique des activités dans le workflow et affiche la relation entre les activités. Il n'est pas impératif d'utiliser la syntaxe d'initialisation d'objet lorsque vous créez des workflows par programmation. L'exemple suivant est d'un point de vue fonctionnel équivalent à l'exemple précédent :

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);

Pour plus d’informations sur les initialiseurs d’objets, consultez Guide pratique : initialiser des objets sans appeler de constructeur (Guide de programmation C#) et Guide pratique : déclarer un objet à l’aide d’un initialiseur d’objet (Visual Basic).

Dans l'exemple suivant, une activité TryCatch est utilisée dans un workflow. Un ApplicationException est levé par le workflow et géré par une activité Catch<TException>. Le gestionnaire de l’action de l’activité Catch<TException> est une activité WriteLine et le détail de l’exception lui est transféré à l’aide du 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."
    }
};

Lorsque vous créez une activité personnalisée qui définit un ActivityAction<T>, utilisez un InvokeAction<T> pour modéliser l'appel de ce ActivityAction<T>. Dans cet exemple, une activité WriteLineWithNotification personnalisée est définie. Cette activité est composée d'un Sequence qui contient une activité WriteLine suivie d'un InvokeAction<T> qui appelle un ActivityAction<T> qui prend un argument de chaîne.

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))
                }
            }
        };
    }
}

Lorsqu'un workflow est créé à l'aide de l'activité WriteLineWithNotification, l'auteur de workflow spécifie la logique personnalisée voulue dans le Handler de l'action de l'activité. Dans cet exemple, un workflow qui utilise l'activité WriteLineWithNotification est créé et une activité WriteLine est utilisée comme 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.

Il existe plusieurs versions génériques de InvokeAction<T> et ActivityAction<T> fournies pour le passage d’un ou de plusieurs arguments.

Utilisation d'ActivityFunc

ActivityAction<T> est utile en l'absence de valeur de résultat de l'activité et ActivityFunc<TResult> est utilisé lorsqu'une valeur de résultat est retournée. Lorsque vous créez une activité personnalisée qui définit un ActivityFunc<TResult>, utilisez un InvokeFunc<TResult> pour modéliser l'appel de ce ActivityFunc<TResult>. Dans l'exemple suivant, une activité WriteFillerText est définie. Pour fournir le texte de remplissage, un InvokeFunc<TResult> qui prend un argument entier et a un résultat de chaîne est spécifié. Une fois le texte de remplissage récupéré, il est affiché sur la console à l'aide d'une activité 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)
                }
            }
        };
    }
}

Pour fournir le texte, une activité qui prend un argument int et a un résultat de chaîne doit être utilisée. Cet exemple montre une activité TextGenerator qui répond à ces critères.

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();
    }
}

Pour utiliser l'activité TextGenerator avec l'activité WriteFillerText, spécifiez-la en tant que 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);