English 中文(简体)
WF4:我如何评估只是常年才知道的表述?
原标题:WF4: How do I evaluate an expression only known at runtime?
  • 时间:2012-04-23 16:43:59
  •  标签:
  • c#
  • .net

I am trying to create a simple WF4 activity that accepts a string that contains a VB.NET expression (from say the database), evaluates that string using the variables available in the current scope of the workflow and returns the result. Unfortunately, with the ways I ve tried it, whether it be with a plain on Activity or a full-fledged NativeActivity, I keep hitting a wall.

我的第一项尝试是简单的活动,我能够做一个简单的班子,评价某些反对的表述作为其投入:

public class Eval<T, TResult> : Activity<TResult>
{
    [RequiredArgument]
    public InArgument<T> Value { get; set; }

    public Eval(string predicate)
    {
        this.Implementation = () => new Assign<TResult>
        {
            Value = new InArgument<TResult>(new VisualBasicValue<TResult>(predicate)),
            To = new ArgumentReference<TResult>("Result")
        };
    }

    public TResult Eval页: 1(T value)
    {
        return WorkflowInvoker.Invoke(this, new Dictionary<string, object>{ {"Value", value } });
    }
}

This woks nicely, and the following expression evaluates to 7:

new Eval<int, int>("Value + 2").Eval页: 1(5)

不幸的是,我可以不使用这种说法,因为表达方式被作为构造论据,而不是作为<条码>的“印章加固”;“,这样它就能够轻易地融入(拖拉和投下)工作流程。 我的第二项尝试是尝试和使用<代码>NativeActivity,以便消除这一浮空构体参数:

public class NativeEval<T, TResult> : NativeActivity<TResult>
{
    [RequiredArgument] public InArgument<string> ExpressionText { get; set; }
    [RequiredArgument] public InArgument<T> Value { get; set; }

    private Assign Assign { get; set; }
    private VisualBasicValue<TResult> Predicate { get; set; }
    private Variable<TResult> ResultVar { get; set; }

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        base.CacheMetadata(metadata);

        Predicate = new VisualBasicValue<TResult>();
        ResultVar = new Variable<TResult>("ResultVar");
        Assign = new Assign { To = new OutArgument<TResult>(ResultVar), Value = new InArgument<TResult>(Predicate) };

        metadata.AddVariable(ResultVar);
        metadata.AddChild(Assign);
    }

    protected override void Execute(NativeActivityContext context)
    {
        Predicate.ExpressionText = ExpressionText.Get(context);
        context.ScheduleActivity(Assign, new CompletionCallback(AssignComplete));
    }

    private void AssignComplete(NativeActivityContext context, ActivityInstance completedInstance)
    {
        Result.Set(context, ResultVar.Get(context));
    }
}

我尝试使用<代码>NativeEval,内容如下:

WorkflowInvoker.Invoke(new NativeEval<int, int>(), new Dictionary<string, object>
    { { "ExpressionText", "Value + 2" }, { "Value", 5 } });

但有以下例外:

活动1:土著人口无法利用这一变量,因为它是在活动范围内宣布的。 1. 土著人口 一项活动只能获得自己的执行变量。

因此,我改变了<代码>metadata。 AddVariable(ResultVar); to metadata.Add ImplementationVariable(ResultVar);,但我却有一个不同的例外:

The following errors were encountered while processing the workflow tree: VariableReference : The referenced Variable object (Name = ResultVar ) is not visible at this scope. There may be another location reference with the same name that is visible at this scope, but it does not reference the same location.

我使用,以安排活动,但所交回的结果总是null <<<>>>>>>>>>:<<0>null>>>>>>>>>>>>>:<<0>null>>><<>>>>>>>>>>>>:<>>>>>>>>null><<<>>>>>>>>>>>>>>>>>>>>>>>:<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>0>>>>>>>>>>>:<>>>>>>>>>>>:<0>>>>

我.。 尽管困难而且往往很耐用(如通常的冶金方案),但至少我能够总结一下我的头脑。 我猜测这种说法,是因为需要代表一个可持久、可再生、不成熟、可搬迁的方案,而不是简单老的方案,这增加了复杂性。


<>光线> 页: 1 我认为,Im试图评估一种code硬编码的表述,不会引起问题Im。

替换

Predicate = new VisualBasicValue<TResult>();

页: 1

Predicate = new VisualBasicValue<TResult>("ExpressionText.Length");

拆除线

Predicate.ExpressionText = ExpressionText.Get(context);

现在,尽管有这些字句是静态的,但我仍然有同样的错误。


EDIT2: This article addressed the exception I was getting. I had to change both variable and child activity to be an "implementation", so this:

metadata.AddVariable(ResultVar);
metadata.AddChild(Assign);

修改如下:

metadata.AddImplementationVariable(ResultVar);
metadata.AddImplementationChild(Assign);

造成所有例外情形消失。 不幸的是,它表明以下两条绝对没有:

Predicate.ExpressionText = ExpressionText.Get(context);

操作期间更改<代码>ExpressionText财产无效力。 与ILSpy的快速核对表明,为什么在要求使用<代码>CacheMetadata()时,仅对表述文本进行评价和转换成表达树,此时这一表述还不知道,这就是为什么我使用了虚构的建造器,该推测并具体化了表达方式。 我甚至试图拯救<条码>。 元数据 物体一载于我自己的CacheMetadata凌驾于登法之上,然后使用反射手段强迫打电话。 视觉基本原理( sCacheMetadata(),但刚刚结束,出现了不同的加密例外(“Ambiguous匹配”)。

此时似乎不可能将动态表述充分纳入工作流程,将其所有内部变量暴露在其中。 我猜测Ill在我的<代码>中使用了何种方法。 Eval category within the NativeEval

最佳回答

我最后使用了以下活动。 它可以不接触工作流程变量,而是接受单一论点。 可在动态表述中使用同一名称的价值。 除此以外,它运作良好。

public class Evaluate<TIn, TOut> : NativeActivity<TOut>
{
    [RequiredArgument]
    public InArgument<string> ExpressionText { get; set; }

    [RequiredArgument]
    public InArgument<TIn> Value { get; set; }

    protected override void Execute(NativeActivityContext context)
    {
        var result = new ExpressionEvaluator<TIn, TOut>(ExpressionText.Get(context)).EvalWith(Value.Get(context));
        Result.Set(context, result);
    }
}

public class ExpressionEvaluator<TIn, TOut> : Activity<TOut>
{
    [RequiredArgument]
    public InArgument<TIn> Value { get; set; }

    public ExpressionEvaluator(string predicate)
    {
        VisualBasic.SetSettingsForImplementation(this, VbSettings);

        Implementation = () => new Assign<TOut>
        {
            Value = new InArgument<TOut>(new VisualBasicValue<TOut>(predicate)),
            To = new ArgumentReference<TOut>("Result")
        };
    }

    public TOut EvalWith(TIn value)
    {
        return WorkflowInvoker.Invoke(this, new Dictionary<string, object> { { "Value", value } });
    }

    private static readonly VisualBasicSettings VbSettings;

    static ExpressionEvaluator()
    {
        VbSettings = new VisualBasicSettings();
        AddImports(typeof(TIn), VbSettings.ImportReferences);
        AddImports(typeof(TOut), VbSettings.ImportReferences);
    }

    private static void AddImports(Type type, ISet<VisualBasicImportReference> imports)
    {
        if (type.IsPrimitive || type == typeof(void) || type.Namespace == "System")
            return;

        var wasAdded = imports.Add(new VisualBasicImportReference { Assembly = type.Assembly.GetName().Name, Import = type.Namespace });

        if (!wasAdded)
            return;

        if (type.BaseType != null)
            AddImports(type.BaseType, imports); 

        foreach (var interfaceType in type.GetInterfaces())
            AddImports(interfaceType, imports);

        foreach (var property in type.GetProperties())
            AddImports(property.PropertyType, imports);

        foreach (var method in type.GetMethods())
        {
            AddImports(method.ReturnType, imports);

            foreach (var parameter in method.GetParameters())
                AddImports(parameter.ParameterType, imports);

            if (method.IsGenericMethod)
            {
                foreach (var genericArgument in method.GetGenericArguments())
                    AddImports(genericArgument, imports);
            }
        }

        if (type.IsGenericType)
        {
            foreach (var genericArgument in type.GetGenericArguments())
                AddImports(genericArgument, imports);
        }
    }
}

www.un.org/spanish/ga/president 更新这一类别,使之包括完整的组装和名称的进口,以免你获得已读(无助)错误信息:

价值没有申报。 由于其保护水平可能无法进入。

此外,将表达器类别移至外并予以公布,因此,你可以在世界基金会之外加以利用,例如:

new ExpressionEvaluator<int, double>("Value * Math.PI").EvalWith(2);

Which will return:

6.28318530717959

问题回答

I would suggest to use a different framework for this. One good approach is to use nCalc. http://ncalc.codeplex.com/

It can parse any expression and evaluate the result, including static or dynamic parameters and custom functions.

We use it to evaluate different kind of expressions at runtime.

如果您的定位是众所周知的扼杀,而不必作一评价的话,你肯定能够做这样的事情,抛弃InArgument,并避免施工者:

public class Eval<T, TResult> : Activity<TResult>
{
    public string Expression { get; set; }

    [RequiredArgument]
    public InArgument<T> Value { get; set; }

    protected override Func<Activity> Implementation
    {
        get
        {
            if (string.IsNullOrEmpty(Expression))
            {
                return base.Implementation;
            }

            return () => new Assign<TResult>
            {
                Value = new InArgument<TResult>(new VisualBasicValue<TResult>(Expression)),
                To = new ArgumentReference<TResult>("Result")
            };
        }
        set
        {
            throw new NotSupportedException();
        }
    }
}

并称之为:

var activity = new Eval<int, int>() { Expression = "Value + 2" };

var inputArgs = new Dictionary<string, object>()
{
    { "Value", 5 }
};

Console.WriteLine("RESULT: " + WorkflowInvoker.Invoke<int>(activity, inputArgs));

<>strong>EDIT: 即便有,也无评论可查:

public class NativeEval<T, TResult> : NativeActivity<TResult>
{
    [RequiredArgument]
    public InArgument<string> ExpressionText { get; set; }
    [RequiredArgument]
    public InArgument<T> Value { get; set; }

    private Assign Assign { get; set; }
    private VisualBasicValue<TResult> Predicate { get; set; }
    private Variable<TResult> ResultVar { get; set; }

    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
        base.CacheMetadata(metadata);

        Predicate = new VisualBasicValue<TResult>("ExpressionText.Length");
        ResultVar = new Variable<TResult>("ResultVar");
        Assign = new Assign { To = new OutArgument<TResult>(ResultVar), Value = new InArgument<TResult>(Predicate) };

        metadata.AddImplementationVariable(ResultVar);
        metadata.AddImplementationChild(Assign);
    }

    protected override void Execute(NativeActivityContext context)
    {
        // this line, commented or not, is the same!
        Predicate.ExpressionText = ExpressionText.Get(context);
        context.ScheduleActivity(Assign, new CompletionCallback(AssignComplete));
    }

    private void AssignComplete(NativeActivityContext context, ActivityInstance completedInstance)
    {
        // the result will always be the ExpressionText.Length 
        Result.Set(context, ResultVar.Get(context));
    }
}

当你在<条码>外币()上使用改变儿童实施情况的方法时,无效果。 执行模式正在发展,儿童树不能改变。





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...