1

我想使用单个参数同时获得编译后的 Func(of boolean) 和 Expression(of Func(of boolean))。我不打算修改表达式树。完全采用表达式树的唯一原因是我可以打印出正在执行的代码。

void Assert(Expression<Func<bool>> assertionExpression) {
    if (!assertionExpression.Compile()()) 
    { 
        throw new AssertFailedException(assertionExpression.ToString()); 
    }
}

有什么合理的方法可以做到这一点吗?

作为一个推论,在简单的编译器生成表达式树的情况下,相同的实例是否总是作为参数传递?

static Dictionary<Expression<Func<bool>>, Func<bool>> cache;

static void Assert(Expression<Func<bool>> assertionExpression) {
    Func<bool> method = null;
    if (!cache.TryGetValue(assertionExpression, out method)) {
        cache.Add(assertionExpression, method = assertionExpression.Compile());
        Console.WriteLine("cache insert");
    }
    else {
         Console.WriteLine("cache hit");
    }
    if (!method()) 
    { 
        throw new AssertFailedException(assertionExpression.ToString()); 
    }
}

static void someCodeThatExecutesRegularly() {
    Assert(()=>true);
}

public static void Main(string[] args, int argc) 
{
    someCodeThatExecutesRegularly();

    someCodeThatExecutesRegularly();

    someCodeThatExecutesRegularly();
}

输出将是“缓存插入”、“缓存命中”、“缓存命中”还是“缓存插入”、“缓存插入”、“缓存插入”。

4

1 回答 1

1

对于第一个问题,您可以获取表达式树并对其进行编译以获得可执行版本,尽管它每次都会重新编译,因此您必须对其进行缓存。

static void Assert(Expression<Func<bool>> assertionExpression) {
    var func = assertionExpression.Compile(); // if you call func() it will execute the expression
}

对于你的第二个问题,它每次都会是一个新的表达式树,所以你会得到“缓存插入”“缓存插入”“缓存插入”等......

要让它与缓存一起工作并进行编译,您可以在表达式上使用 .ToString() 来获取函数的字符串表示,但是如果您有任何闭包,这可能会导致非常混乱的问题,因为字符串表示可能相同但是封闭的变量会有所不同,因此如果您这样做,请谨慎使用!

于 2012-05-24T17:32:39.543 回答