尝试执行复杂的匿名方法失败了

时间:2011-07-22 14:06:42

标签: linq

更新(愚蠢失败)

那么,在我所有复杂的公式代码中,我忽略了C#的基本原理。

  

方法可能会返回一个值。

static dynamic Construct<T>(T expression){
    return expression;
}

然后只使用它,而不是变量......

Method = Construct<Action<Context, string, int>>(
                        (context, key, change) =>
                            {
                                context.Saved[key] += change;

                                Console.WriteLine("{0}'s saved value of {1} was changed by {2}, resulting in {3}",
                                    context.Name, key, change, context.Saved[key]);
                            }
                        )

我有一种情况需要调用不存在的编译方法,而是需要能够接受参数数组并作为匿名函数执行。我以为我已经解决了问题,但我遇到了以下问题..

public static IDictionary<string, Function> Expressions =
            new Dictionary<string, Function> {
            {
                "Increase [X] by value of [Y]",
                new Function {
                    Name = "Increase [X] by [Y]",
                    Parameters = 2,
                    Types = new List<Type>{
                        typeof(Param),
                        typeof(Param)
                    },
                    Method = (Expression<Func<Context, Param, Param, bool>>)
                                ((context, x, y) => {
                                    Console.WriteLine("test"); // this is where I need to do stuff... 
                                })
                }
            }
        };

我被告知Method name is expected就此而言。问题是Context将由接受该函数并运行其方法的对象传入,因为Context对象不能预先绑定(它必须是后期绑定的)。所以基本上我在这种情况下打包了尾随的2个参数(Param)和(Param)并创建了一个对它们执行的函数。

数据库存储这些参数,然后使用Context调用传入相应Compile().DynamicInvoke(object[] params)作为第一个参数的方法。

有人可以帮我解释为什么我不能在{ }之间加入任何逻辑吗?

更新

好的,既然我被告知这个例子还不清楚,这里有一个完整的程序从头到尾完成,说明我想要完成的任务。

public class Program {
    static void Main(string[] args) {
        // simple object stored in database.
        var ctx = new Context {
            Name = "Ciel",
            Saved = new Dictionary<string, int> {
                { "First", 10 },
                { "Second", 20 }
            }
        };
        // simple object stored in database.
        var rule = new Rule {
            Equations = new List<Equation> {
                new Equation {
                    Parameters = new List<object>{
                        "First",
                        5
                    },
                    Name = "Increase [X] by value of [Y]"
                }
            }
        };

        // =======================================
        // runtime environment!!!
        // =======================================
        var method = Evaluations.Expressions[rule.Equations[0].Name].Method;
        var parameters = rule.Equations[0].Parameters;

        // insert the specific context as the first parameter.
        parameters.Insert(0, ctx);
        method.DynamicInvoke(parameters.ToArray());

        Console.ReadLine();
    }
}

public class Function {
    public string Name { get; set; }
    public dynamic Method { get; set; }
}

public class Equation {
    public string Name { get; set; }
    // these objects will be simple enough to serialize.
    public IList<object> Parameters { get; set; }
    public Function Function { get; set; }
}

public class Context {
    public string Name { get; set; }
    // this is a crude example, but it serves the demonstration purposes.
    public IDictionary<string, int> Saved { get; set; }
}

public class Rule {
    // again, a crude example.
    public IList<Equation> Equations { get; set; }
}

public static class Evaluations {
    static Action<Context, string, int> expr = (context, key, change) =>
        {
                context.Saved[key] += change;

                Console.WriteLine("{0}'s saved value of {1} was changed by {2}, resulting in {3}",
                    context.Name, key, change, context.Saved[key]);
            };

    public static IDictionary<string, Function> Expressions =
        new Dictionary<string, Function> {
        {
            "Increase [X] by value of [Y]",
            new Function {
                Name = "Increase [X] by [Y]",
                Method = expr
            }
        }
    };
}

2 个答案:

答案 0 :(得分:2)

四个问题:

  • 您正在尝试使用语句主体(即大括号)从lambda表达式创建表达式树。 C#不允许这样做 - 您只能将语句lambda转换为委托,而不是表达式树
  • 您的lambda主体不返回布尔值
  • 您尝试将Expression<Func<Context, Param, Param, bool>>称为具有bool参数的方法。你在那里尝试做什么并不清楚。
  • 即使第三点 有效,我怀疑你需要更多括号。

答案 1 :(得分:1)

如果您重构代码以使其更具可读性和可管理性,那么您可能会很好地解决问题。而不是使用单个分号的一个庞大的C#语句,将其分成几行。像这样:

public static Dictionary<string, Function> Expressions = getExpressions();

private static Dictionary<string, Function> getExpressions()
{   
    var method = (Expression<Func<Context, Param, Param, bool>>)
                    ((context, x, y) => {
                        Console.WriteLine("test"); // this is where I need to do stuff... 
                    })(true);

    var func = new Function()
    {
        Name = "Increase [X] by [Y]",
        Parameters = 2,
        Types = new List<Type>
        {
            typeof(Param),
            typeof(Param)
        },
        Method = method
    };

    var dict = new Dictionary<string, Function>();
    dict["Increase [X] by value of [Y]"] = func;
    return dict;
}

注意:我的语法可能不正确,但您可以得到一般的想法。