Udostępnij za pośrednictwem


Używanie delegatów działania

Delegaty działań umożliwiają autorom działań uwidacznienie wywołań zwrotnych przy użyciu określonych podpisów, dla których użytkownicy działania mogą udostępniać programy obsługi oparte na działaniach. Dostępne są dwa typy delegatów działań: ActivityAction<T> służy do definiowania delegatów działań, które nie mają wartości zwracanej, i ActivityFunc<TResult> służy do definiowania delegatów działań, które mają wartość zwracaną.

Delegaty działań są przydatne w scenariuszach, w których działanie podrzędne musi być ograniczone do posiadania określonego podpisu. Na przykład While działanie może zawierać dowolny typ działania podrzędnego bez ograniczeń, ale treść ForEach<T> działania jest działaniem ActivityAction<T>podrzędnym, które jest ostatecznie wykonywane przez ForEach<T> program, musi mieć InArgument<T> ten sam typ elementów członkowskich kolekcji, które ForEach<T> wylicza.

Korzystanie z działaniaAction

Kilka działań programu .NET Framework 4.6.1 używa akcji działań, takich jak Catch działanie i ForEach<T> działanie. W każdym przypadku akcja działania reprezentuje lokalizację, w której autor przepływu pracy określa działanie w celu zapewnienia żądanego zachowania podczas tworzenia przepływu pracy przy użyciu jednego z tych działań. W poniższym przykładzie działanie ForEach<T> służy do wyświetlania tekstu w oknie konsoli. Treść obiektu ForEach<T> jest określana przy użyciu elementu ActivityAction<T> , który odpowiada typowi ForEach<T> ciągu. Działanie WriteLine określone w Handler obiekcie ma swój Text argument powiązany z wartościami ciągu w kolekcji, które ForEach<T> iteruje działanie.

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

AkcjaArgument służy do przepływu poszczególnych elementów w kolekcji do funkcji WriteLine. Po wywołaniu przepływu pracy następujące dane wyjściowe zostaną wyświetlone w konsoli programu .

HelloWorld.

Przykłady w tym temacie używają składni inicjowania obiektów. Składnia inicjowania obiektów może być przydatnym sposobem tworzenia definicji przepływu pracy w kodzie, ponieważ zapewnia hierarchiczny widok działań w przepływie pracy i pokazuje relację między działaniami. Podczas programowego tworzenia przepływów pracy nie trzeba używać składni inicjowania obiektów. Poniższy przykład jest funkcjonalnie odpowiednikiem poprzedniego przykładu.

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

Aby uzyskać więcej informacji na temat inicjatorów obiektów, zobacz How to: Initialize Objects without Calling a Constructor (Przewodnik programowania w języku C#) i How to: Declare an Object By Using an Object Initializer (Visual Basic)( Jak zadeklarować obiekt za pomocą inicjatora obiektów (Visual Basic).

W poniższym przykładzie działanie TryCatch jest używane w przepływie pracy. Element ApplicationException jest zgłaszany przez przepływ pracy i jest obsługiwany przez Catch<TException> działanie. Procedura obsługi Catch<TException> akcji działania działania jest działaniem WriteLine , a szczegóły wyjątku są przekazywane do niego przy użyciu elementu 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."
    }
};

Podczas tworzenia niestandardowego działania, które definiuje ActivityAction<T>element , użyj elementu InvokeAction<T> do modelowania wywołania tego ActivityAction<T>elementu . W tym przykładzie zdefiniowano działanie niestandardowe WriteLineWithNotification . To działanie składa się z Sequence obiektu zawierającego WriteLine działanie, po którym następuje wywołanie argumentu ActivityAction<T> InvokeAction<T> , który przyjmuje jeden argument ciągu.

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

Po utworzeniu WriteLineWithNotification przepływu pracy przy użyciu działania autor przepływu pracy określa żądaną logikę niestandardową w akcji Handlerdziałania . W tym przykładzie tworzony jest przepływ pracy, który używa WriteLineWithNotification działania, a WriteLine działanie jest używane jako 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.

Istnieje wiele wersji InvokeAction<T> ogólnych i ActivityAction<T> dostępnych do przekazywania co najmniej jednego argumentu.

Korzystanie z funkcji ActivityFunc

ActivityAction<T> jest przydatna, gdy nie ma wartości wyniku z działania i ActivityFunc<TResult> jest używana, gdy zwracana jest wartość wyniku. Podczas tworzenia niestandardowego działania, które definiuje ActivityFunc<TResult>element , użyj elementu InvokeFunc<TResult> do modelowania wywołania tego ActivityFunc<TResult>elementu . W poniższym przykładzie zdefiniowano WriteFillerText działanie. Aby podać tekst wypełniacza, InvokeFunc<TResult> określony element przyjmuje argument liczby całkowitej i ma wynik ciągu. Po pobraniu tekstu wypełnienia zostanie on wyświetlony w konsoli przy użyciu WriteLine działania.

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

Aby podać tekst, należy użyć działania, które przyjmuje jeden int argument i ma wynik ciągu. W tym przykładzie pokazano TextGenerator działanie spełniające te wymagania.

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

Aby użyć TextGenerator działania z działaniem WriteFillerText , określ je jako 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);