c# - 工作坊 4.5。将 C# 表达式与外部类引用一起使用

标签 c# workflow-foundation

我正在尝试使用新的 WF 4.5 功能 - C# 表达式编译动态事件。 它一直有效,直到我在表达式中添加一个外部类。

如果表达式包含基本对象,它就会被编译。 如果我添加对外部类的引用,它会生成错误“找不到类型或命名空间名称‘xxxxx’(是否缺少 using 指令或程序集引用?)”

那么,问题是如何为 C# 表达式引用外部类?

附言它适用于 VisualBasic 表达式类型

谢谢

//Compiled without errors
var errorCodeWorkflow = new DynamicActivity
{
    Name = "DynamicActivity",
    Implementation = () => new WriteLine
    {
        Text = new CSharpValue<String>
        {
            ExpressionText = "new Random().Next(1, 101).ToString()"
        }
     }
};

CompileExpressions(errorCodeWorkflow);
WorkflowInvoker.Invoke(errorCodeWorkflow);


//Error 

using System;
using System.Activities;
using System.Activities.Expressions;
using System.Activities.Statements;
using System.Activities.XamlIntegration;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CSharp.Activities;

namespace CSharpExpression 
{
    class Program
    {
        static void Main()
        {
            var errorCodeWorkflow = new DynamicActivity
            {
                Name = "MyScenario.MyDynamicActivity3",
                Properties =
                {
                    new DynamicActivityProperty
                    {
                        Name = "Address",
                        Type = typeof(InArgument<MailAddress>),
                    },
                },
                Implementation = () => new WriteLine
                {
                    Text = new CSharpValue<String>
                    {
                        ExpressionText = "\"MyDynamicActivity \" + Address.DisplayName"
                    }
                }
            };

            CompileExpressions(errorCodeWorkflow);
            WorkflowInvoker.Invoke(errorCodeWorkflow, new Dictionary<String, Object> { { "Address", new MailAddress { DisplayName = "TestDisplayName" } } });
        }

        static void CompileExpressions(DynamicActivity dynamicActivity)
        {
            var activityName = dynamicActivity.Name;
            var activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
            var activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());

            var settings = new TextExpressionCompilerSettings
            {
                Activity = dynamicActivity,
                Language = "C#",
                ActivityName = activityType,
                ActivityNamespace = activityNamespace,
                RootNamespace = "CSharpExpression",
                GenerateAsPartialClass = false,
                AlwaysGenerateSource = true,
                ForImplementation = true
            };

            var results = new TextExpressionCompiler(settings).Compile();

            if (results.HasErrors)
            {
                throw new Exception("Compilation failed.");
            }

            var compiledExpressionRoot = Activator.CreateInstance(results.ResultType, new object[] { dynamicActivity }) as ICompiledExpressionRoot;
            CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation(dynamicActivity, compiledExpressionRoot);
        }
    }

    public class MailAddress
    {
        public String Address { get; set; }
        public String DisplayName { get; set; }
    }
}

最佳答案

我在处理非动态事件时遇到了一个相同的问题,现在已经检查了使它起作用所需的条件:

总结

  1. 添加对System.Xaml

    的引用
  2. MailAddress 移动到不同的命名空间。

  3. 动态事件添加一些关于您的类来自何处的信息:

var impl = new AttachableMemberIdentifier(typeof(TextExpression), "NamespacesForImplementation");
var namespaces = new List<string> { typeof(MailAddress).Namespace };
TextExpression.SetReferencesForImplementation(dynamicActivity, new AssemblyReference { Assembly = typeof(MailAddress).Assembly });
AttachablePropertyServices.SetProperty(dynamicActivity, impl, namespaces);

为了得到这个答案,我需要深入研究 TextExpressionCompiler 源代码,这样可能会有更优雅的东西。


非动态事件

如果您不使用动态事件,则对 CompileExpressions 的调用将按照此处所述进行更改:http://msdn.microsoft.com/en-us/library/jj591618.aspx .

向事件添加信息将通过删除“ForImplementation”部分进行修改:

var impl = new AttachableMemberIdentifier(typeof(TextExpression), "Namespaces");
var namespaces = new List<string> { typeof(MailAddress).Namespace };
TextExpression.SetReferences(nonDynamicActivity, new AssemblyReference { Assembly = typeof(MailAddress).Assembly });
AttachablePropertyServices.SetProperty(nonDynamicActivity, impl, namespaces);

工作代码

using System;
using System.Activities;
using System.Activities.Expressions;
using System.Activities.Statements;
using System.Activities.XamlIntegration;
using System.Collections.Generic;
using System.Linq;
using System.Xaml;
using ExternalNamespace;
using Microsoft.CSharp.Activities;

namespace CSharpExpression 
{
    class Program
    {
        static void Main()
        {
            var errorCodeWorkflow = new DynamicActivity
            {
                Name = "MyScenario.MyDynamicActivity3",
                Properties =
                {
                    new DynamicActivityProperty
                    {
                        Name = "Address",
                        Type = typeof(InArgument<MailAddress>),
                    },
                },
                Implementation = () => new WriteLine
                {
                    Text = new CSharpValue<String>
                    {
                        ExpressionText = "\"MyDynamicActivity \" + Address.DisplayName"
                    }
                }
            };

            var impl = new AttachableMemberIdentifier(typeof(TextExpression), "NamespacesForImplementation");
            var namespaces = new List<string> { typeof(MailAddress).Namespace };
            TextExpression.SetReferencesForImplementation(errorCodeWorkflow, new AssemblyReference { Assembly = typeof(MailAddress).Assembly });
            AttachablePropertyServices.SetProperty(errorCodeWorkflow, impl, namespaces);

            CompileExpressions(errorCodeWorkflow);
            WorkflowInvoker.Invoke(errorCodeWorkflow, new Dictionary<String, Object> { { "Address", new MailAddress { DisplayName = "TestDisplayName" } } });
        }

        static void CompileExpressions(DynamicActivity dynamicActivity)
        {
            var activityName = dynamicActivity.Name;
            var activityType = activityName.Split('.').Last() + "_CompiledExpressionRoot";
            var activityNamespace = string.Join(".", activityName.Split('.').Reverse().Skip(1).Reverse());

            var settings = new TextExpressionCompilerSettings
            {
                Activity = dynamicActivity,
                Language = "C#",
                ActivityName = activityType,
                ActivityNamespace = activityNamespace,
                RootNamespace = "CSharpExpression",
                GenerateAsPartialClass = false,
                AlwaysGenerateSource = true,
                ForImplementation = true
            };

            var results = new TextExpressionCompiler(settings).Compile();

            if (results.HasErrors)
            {
                throw new Exception("Compilation failed.");
            }

            var compiledExpressionRoot = Activator.CreateInstance(results.ResultType, new object[] { dynamicActivity }) as ICompiledExpressionRoot;
            CompiledExpressionInvoker.SetCompiledExpressionRootForImplementation(dynamicActivity, compiledExpressionRoot);
        }
    }
}

namespace ExternalNamespace
{
    public class MailAddress
    {
        public String Address { get; set; }
        public String DisplayName { get; set; }
    }
}

关于c# - 工作坊 4.5。将 C# 表达式与外部类引用一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16086612/

相关文章:

c# - 避免在 native 到托管回调上分配字符串

c# - MailKit:如何迭代最近的电子邮件以获取具有给定主题的电子邮件

workflow - WF 的有力案例

c# - 如何使用c#计算带宽

c# - 为什么这个 System.InvalidOperationException 目标向后?

c# - nservicebus启动错误

multithreading - 单线程单元中的工作流程 4.0?

c# - 在 ASP.NET MVC 中使用状态机工作流

asp.net-mvc - 使用 ASP.Net MVC 的状态机工作流程

c# - 将多个属性元数据添加到工作流事件中的依赖属性