共用方式為


C# 運算式

從 .NET Framework 4.5 開始,Windows Workflow Foundation (WF) 支援 C# 表達式。 以 .NET Framework 4.5 為目標的 Visual Studio 2012 中建立的新 C# 工作流程專案會使用 C# 表達式,而 Visual Basic 工作流程專案則使用 Visual Basic 表達式。 不論專案語言為何,使用 Visual Basic 表達式的現有 .NET Framework 4 工作流程專案都可以遷移至 .NET Framework 4.6.1,並且受到支援。 本主題提供 WF 中 C# 表達式的概觀。

在工作流程中使用 C# 運算式

在工作流程設計工具中使用 C# 運算式

從 .NET Framework 4.5 開始,Windows Workflow Foundation (WF) 支援 C# 表達式。 以 .NET Framework 4.5 為目標的 Visual Studio 2012 中建立的 C# 工作流程專案會使用 C# 表達式,而 Visual Basic 工作流程專案則使用 Visual Basic 表達式。 若要指定所需的 C# 運算式,請在標示為 Enter a C# 運算式的方塊中輸入它。 當在設計工具中選取活動或工作流程設計工具中的活動時,此標籤會顯示在屬性視窗中。 在下列範例中,兩個WriteLine活動包含在Sequence中,且Sequence位於內。

自動建立之序列活動的螢幕快照。

備註

C# 運算式僅在 Visual Studio 中受到支援,而且在重新裝載的工作流程設計工具中不支援。 如需重新裝載設計工具中支援的新 WF45 功能詳細資訊,請參閱 重新裝載工作流程設計工具中的新 Workflow Foundation 4.5 功能支援

回溯相容性

支援已移轉至 .NET Framework 4.6.1 的現有 .NET Framework 4 C# 工作流程專案中的 Visual Basic 表達式。 在工作流程設計工具中檢視 Visual Basic 運算式時,如果 Visual Basic 運算式不是有效的 C# 語法,那麼現有的 Visual Basic 運算式文字會被替換為 Value was set in XAML。 如果 Visual Basic 運算式是有效的 C# 語法,則會顯示表示式。 若要將 Visual Basic 運算式更新為 C#,您可以在工作流程設計工具中編輯它們,並指定對等的 C# 運算式。 不需要將 Visual Basic 運算式更新為 C#,但是一旦工作流程設計工具中更新運算式,它們就會轉換成 C#,而且可能不會還原為 Visual Basic。

在程序代碼工作流程中使用 C# 運算式

.NET Framework 4.6.1 的基於程式碼的工作流程支援 C# 表達式,但在呼叫工作流程之前,必須使用 TextExpressionCompiler.Compile 編譯這些 C# 表達式。 工作流程作者可以使用 CSharpValue 來表示表達式的 r 值,以及 CSharpReference 表示表達式的 l 值。 在下列範例中,會建立一個包含 Assign 活動和 WriteLine 活動於 Sequence 活動中的工作流程。 為 CSharpReferenceTo 自變數指定 Assign ,並表示表達式的 l 值。 CSharpValueValueAssign參數指定,並且為TextWriteLine參數指定,均表示這兩個表達式的 r 值。

Variable<int> n = new Variable<int>
{
    Name = "n"
};

Activity wf = new Sequence
{
    Variables = { n },
    Activities =
    {
        new Assign<int>
        {
            To = new CSharpReference<int>("n"),
            Value = new CSharpValue<int>("new Random().Next(1, 101)")
        },
        new WriteLine
        {
            Text = new CSharpValue<string>("\"The number is \" + n")
        }
    }
};

CompileExpressions(wf);

WorkflowInvoker.Invoke(wf);

建構工作流程之後,C# 表達式會藉由呼叫 CompileExpressions 協助程式方法來編譯,然後叫用工作流程。 下列範例是 CompileExpressions 方法。

static void CompileExpressions(Activity activity)
{
    // activityName is the Namespace.Type of the activity that contains the
    // C# expressions.
    string activityName = activity.GetType().ToString();

    // Split activityName into Namespace and Type.Append _CompiledExpressionRoot to the type name
    // to represent the new type that represents the compiled expressions.
    // Take everything after the last . for the type name.
    string activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
    // Take everything before the last . for the namespace.
    string activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());

    // Create a TextExpressionCompilerSettings.
    TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
    {
        Activity = activity,
        Language = "C#",
        ActivityName = activityType,
        ActivityNamespace = activityNamespace,
        RootNamespace = null,
        GenerateAsPartialClass = false,
        AlwaysGenerateSource = true,
        ForImplementation = false
    };

    // Compile the C# expression.
    TextExpressionCompilerResults results =
        new TextExpressionCompiler(settings).Compile();

    // Any compilation errors are contained in the CompilerMessages.
    if (results.HasErrors)
    {
        throw new Exception("Compilation failed.");
    }

    // Create an instance of the new compiled expression type.
    ICompiledExpressionRoot compiledExpressionRoot =
        Activator.CreateInstance(results.ResultType,
            new object[] { activity }) as ICompiledExpressionRoot;

    // Attach it to the activity.
    CompiledExpressionInvoker.SetCompiledExpressionRoot(
        activity, compiledExpressionRoot);
}

備註

如果未編譯 C# 運算式, NotSupportedException 當工作流程叫用類似如下的訊息時,會擲回 : Expression Activity type 'CSharpValue1' 需要編譯才能執行。 請確保工作流程已完成編譯。

如果您的自定義程式碼工作流程使用 DynamicActivity,則需要對 方法進行一些變更 CompileExpressions ,如下列程式代碼範例所示。

static void CompileExpressions(DynamicActivity dynamicActivity)
{
    // activityName is the Namespace.Type of the activity that contains the
    // C# expressions. For Dynamic Activities this can be retrieved using the
    // name property , which must be in the form Namespace.Type.
    string activityName = dynamicActivity.Name;

    // Split activityName into Namespace and Type.Append _CompiledExpressionRoot to the type name
    // to represent the new type that represents the compiled expressions.
    // Take everything after the last . for the type name.
    string activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
    // Take everything before the last . for the namespace.
    string activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());

    // Create a TextExpressionCompilerSettings.
    TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
    {
        Activity = dynamicActivity,
        Language = "C#",
        ActivityName = activityType,
        ActivityNamespace = activityNamespace,
        RootNamespace = null,
        GenerateAsPartialClass = false,
        AlwaysGenerateSource = true,
        ForImplementation = true
    };

    // Compile the C# expression.
    TextExpressionCompilerResults results =
        new TextExpressionCompiler(settings).Compile();

    // Any compilation errors are contained in the CompilerMessages.
    if (results.HasErrors)
    {
        throw new Exception("Compilation failed.");
    }

    // Create an instance of the new compiled expression type.
    ICompiledExpressionRoot compiledExpressionRoot =
        Activator.CreateInstance(results.ResultType,
            new object[] { dynamicActivity }) as ICompiledExpressionRoot;

    // Attach it to the activity.
    CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation(
        dynamicActivity, compiledExpressionRoot);
}

CompileExpressions 動態活動中編譯 C# 表達式的多載具有幾個不同之處。

  • CompileExpressions參數是 DynamicActivity

  • 類型名稱和命名空間是使用 DynamicActivity.Name 屬性來擷取。

  • TextExpressionCompilerSettings.ForImplementation 設定為 true

  • CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation 被呼叫 而不是 CompiledExpressionInvoker.SetCompiledExpressionRoot

如需在程式代碼中使用表達式的詳細資訊,請參閱 使用命令式程式碼撰寫工作流程、活動和表示式

在 XAML 工作流程中使用 C# 運算式

XAML 工作流程支援 C# 運算式。 編譯的 XAML 工作流程會被編譯成一種類型,而在執行階段,鬆散的 XAML 工作流程會先被載入,然後在執行工作流程時編譯成活動樹狀結構。

已編譯的 Xaml

編譯的 XAML 工作流程支援 C# 運算式,這些工作流程會編譯為以 .NET Framework 4.6.1 為目標的 C# 工作流程專案的一部分。 編譯的 XAML 是 Visual Studio 中工作流程撰寫的預設類型,而以 .NET Framework 4.6.1 為目標的 Visual Studio 中建立的 C# 工作流程專案會使用 C# 表達式。

非編譯 XAML

鬆散的 XAML 工作流程支援 C# 運算式。 載入和叫用鬆散 XAML 工作流程的工作流程主機程式必須以 .NET Framework 4.6.1 為目標,而且 CompileExpressions 必須設定為 true (預設值為 false)。 若要設定 CompileExpressionstrue,請建立一個 ActivityXamlServicesSettings 實體,將其 CompileExpressions 屬性設定為 true,然後將它當做參數傳遞至 ActivityXamlServices.Load。 如果 CompileExpressions 未設定為 true,將引發 NotSupportedException 並顯示類似以下的訊息: 'Expression Activity type 'CSharpValue1' 需要編譯才能執行。 請確保工作流程已完成編譯。

ActivityXamlServicesSettings settings = new ActivityXamlServicesSettings
{
    CompileExpressions = true
};

DynamicActivity<int> wf = ActivityXamlServices.Load(new StringReader(serializedAB), settings) as DynamicActivity<int>;

如需使用 XAML 工作流程的詳細資訊,請參閱 序列化 XAML 的工作流程和活動

在 XAMLX 工作流程服務中使用 C# 運算式

XAMLX 工作流程服務支援 C# 運算式。 當工作流程服務裝載於 IIS 或 WAS 時,不需要其他步驟,但如果 XAML 工作流程服務是自我裝載的,則必須編譯 C# 運算式。 若要在自我裝載的 XAMLX 工作流程服務中編譯 C# 運算式,請先將 XAMLX 檔案載入WorkflowService,然後將BodyWorkflowService 傳遞至先前在CompileExpressions一節中所述的方法。 在下列範例中,會載入 XAMLX 工作流程服務、編譯 C# 表達式,然後開啟工作流程服務並等候要求。

// Load the XAMLX workflow service.
WorkflowService workflow1 =
    (WorkflowService)XamlServices.Load(xamlxPath);

// Compile the C# expressions in the workflow by passing the Body to CompileExpressions.
CompileExpressions(workflow1.Body);

// Initialize the WorkflowServiceHost.
var host = new WorkflowServiceHost(workflow1, new Uri("http://localhost:8293/Service1.xamlx"));

// Enable Metadata publishing/
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);

// Open the WorkflowServiceHost and wait for requests.
host.Open();
Console.WriteLine("Press enter to quit");
Console.ReadLine();

如果未編譯 C# 運算式,作業 Open 會成功,但叫用工作流程時將會失敗。 下列 CompileExpressions 方法與先前 在程序代碼工作流程中使用 C# 運算式 一節中的 方法相同。

static void CompileExpressions(Activity activity)
{
    // activityName is the Namespace.Type of the activity that contains the
    // C# expressions.
    string activityName = activity.GetType().ToString();

    // Split activityName into Namespace and Type.Append _CompiledExpressionRoot to the type name
    // to represent the new type that represents the compiled expressions.
    // Take everything after the last . for the type name.
    string activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
    // Take everything before the last . for the namespace.
    string activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());

    // Create a TextExpressionCompilerSettings.
    TextExpressionCompilerSettings settings = new TextExpressionCompilerSettings
    {
        Activity = activity,
        Language = "C#",
        ActivityName = activityType,
        ActivityNamespace = activityNamespace,
        RootNamespace = null,
        GenerateAsPartialClass = false,
        AlwaysGenerateSource = true,
        ForImplementation = false
    };

    // Compile the C# expression.
    TextExpressionCompilerResults results =
        new TextExpressionCompiler(settings).Compile();

    // Any compilation errors are contained in the CompilerMessages.
    if (results.HasErrors)
    {
        throw new Exception("Compilation failed.");
    }

    // Create an instance of the new compiled expression type.
    ICompiledExpressionRoot compiledExpressionRoot =
        Activator.CreateInstance(results.ResultType,
            new object[] { activity }) as ICompiledExpressionRoot;

    // Attach it to the activity.
    CompiledExpressionInvoker.SetCompiledExpressionRoot(
        activity, compiledExpressionRoot);
}