C# 表达式的增量值

C# 表达式的增量值,c#,.net,reflection,code-generation,linq-expressions,C#,.net,Reflection,Code Generation,Linq Expressions,我想写一个闭包并增加它的值,但我不能这样做。这是我的密码 int i = 0; Expression<Func<bool>> closurExpression = () => { i++;

我想写一个闭包并增加它的值,但我不能这样做。这是我的密码

        int i = 0;
        Expression<Func<bool>> closurExpression = () =>
                                                  {
                                                      i++;
                                                      return i != 0;
                                                  };
我第一次意识到:

class FunctionWithCounter<T, TResult>
{
    private readonly Func<T, TResult> function;
    public int Calls { get; set; }

    private FunctionWithCounter(Func<T, TResult> function)
    {
        Calls = 0;
        this.function = function;
    }
    public static implicit operator FunctionWithCounter<T, TResult>(Func<T, TResult> func)
    {
        return new FunctionWithCounter<T, TResult>(func);
    }

    public TResult this[T arg]
    {
        get
        {
            Calls++;
            return function(arg);
        }
    }
}
我的第二个实现是基于Emit API的,但它太复杂了,而且很长一段时间都没有完成

这是我第三次尝试,我想使用表达式。Ⅸt应如下所示:

    public FunctionWithCounter(Expression<Func<T, TResult>> function)
    {
        Action action = () => _calls++;
        Expression<Action> closurExpression = () => action();
        var result = Expression.Block(closurExpression, function);
        _functionWithInjection = Expression.Lambda<Func<T,TResult>>(result).Compile();
    }
var rw = new RecursiveFunctionWithCounter<int, int>(
        (n, self) => { return n < 2 ? 1 : n * self[n - 1]; }
);

int rr = rw[3]; // rr=6
int rc = rw.Calls; // rc=3
带计数器的公共函数(表达式函数)
{
动作动作=()=>u调用++;
表达式closurExpression=()=>action();
var result=Expression.Block(closurExpression,function);
_functionWithInjection=Expression.Lambda(result.Compile();
}

对不起,我的英语不好,但我真的很想实现这个想法。

好吧,你可以使用
联锁来避开规则。增量

int i = 0;
Expression<Func<bool>> expression = () => Interlocked.Increment(ref i) != 0;
inti=0;
表达式=()=>互锁。增量(参考i)!=0;
。。。但我会非常谨慎地这样做。考虑到涉及的副作用,我不希望有很多处理表达式树的代码能够非常干净地处理这个问题

就我所期望的行为方式而言,上述措施似乎确实有效:

int i = -2;
Expression<Func<bool>> expression = () => Interlocked.Increment(ref i) != 0;
var del = expression.Compile();
Console.WriteLine(del()); // True
Console.WriteLine(del()); // False
Console.WriteLine(del()); // True
Console.WriteLine(del()); // True
Console.WriteLine(i);     // 2
inti=-2;
表达式=()=>互锁。增量(参考i)!=0;
var del=expression.Compile();
Console.WriteLine(del());//符合事实的
Console.WriteLine(del());//错误的
Console.WriteLine(del());//符合事实的
Console.WriteLine(del());//符合事实的
Console.WriteLine(一);//2.

好吧,您可以使用
联锁来避开规则。增量

int i = 0;
Expression<Func<bool>> expression = () => Interlocked.Increment(ref i) != 0;
inti=0;
表达式=()=>互锁。增量(参考i)!=0;
。。。但我会非常谨慎地这样做。考虑到涉及的副作用,我不希望有很多处理表达式树的代码能够非常干净地处理这个问题

就我所期望的行为方式而言,上述措施似乎确实有效:

int i = -2;
Expression<Func<bool>> expression = () => Interlocked.Increment(ref i) != 0;
var del = expression.Compile();
Console.WriteLine(del()); // True
Console.WriteLine(del()); // False
Console.WriteLine(del()); // True
Console.WriteLine(del()); // True
Console.WriteLine(i);     // 2
inti=-2;
表达式=()=>互锁。增量(参考i)!=0;
var del=expression.Compile();
Console.WriteLine(del());//符合事实的
Console.WriteLine(del());//错误的
Console.WriteLine(del());//符合事实的
Console.WriteLine(del());//符合事实的
Console.WriteLine(一);//2.

我认为您的第一种方法对于简单的、非递归的情况来说更干净、更合适。 如果您允许您的包装函数意识到递归,那么您可以更进一步,使包装函数成为函数本身的参数:

 class RecursiveFunctionWithCounter<T, TResult> 
 {
    private readonly Func<T, RecursiveFunctionWithCounter<T, TResult>, TResult> function;
    public int Calls { get; set; }

    public RecursiveFunctionWithCounter(Func<T, RecursiveFunctionWithCounter<T, TResult>, TResult> function)
    {
        Calls = 0;
        this.function = function;
    }


    public TResult this[T arg]
    {
        get
        {
            Calls++;
            return function(arg, this);
        }
    }
 }
使用计数器初始化递归函数
{
私有只读函数;
公共int调用{get;set;}
带计数器的公共递归函数(Func函数)
{
调用=0;
这个函数=函数;
}
public TResult this[T arg]
{
收到
{
调用++;
返回函数(arg,this);
}
}
}
然后像这样使用它:

    public FunctionWithCounter(Expression<Func<T, TResult>> function)
    {
        Action action = () => _calls++;
        Expression<Action> closurExpression = () => action();
        var result = Expression.Block(closurExpression, function);
        _functionWithInjection = Expression.Lambda<Func<T,TResult>>(result).Compile();
    }
var rw = new RecursiveFunctionWithCounter<int, int>(
        (n, self) => { return n < 2 ? 1 : n * self[n - 1]; }
);

int rr = rw[3]; // rr=6
int rc = rw.Calls; // rc=3
var rw=带计数器的新递归函数(
(n,self)=>{returnn<2?1:n*self[n-1];}
);
int rr=rw[3];//rr=6
int rc=rw.Calls;//rc=3

另一方面,如果您真正想要做的是在代码中检测一些现有的方法,那么请考虑做一点(例如,这是在每个方法调用上增加性能计数器的一个方面)。通过这种方式,您可以在方法中添加一个属性,如
IncrementPerformanceCounterAttribute
,AOT库将完成其余的工作。

我认为您的第一种方法更简洁,适用于简单、非递归的情况。 如果您允许您的包装函数意识到递归,那么您可以更进一步,使包装函数成为函数本身的参数:

 class RecursiveFunctionWithCounter<T, TResult> 
 {
    private readonly Func<T, RecursiveFunctionWithCounter<T, TResult>, TResult> function;
    public int Calls { get; set; }

    public RecursiveFunctionWithCounter(Func<T, RecursiveFunctionWithCounter<T, TResult>, TResult> function)
    {
        Calls = 0;
        this.function = function;
    }


    public TResult this[T arg]
    {
        get
        {
            Calls++;
            return function(arg, this);
        }
    }
 }
使用计数器初始化递归函数
{
私有只读函数;
公共int调用{get;set;}
带计数器的公共递归函数(Func函数)
{
调用=0;
这个函数=函数;
}
public TResult this[T arg]
{
收到
{
调用++;
返回函数(arg,this);
}
}
}
然后像这样使用它:

    public FunctionWithCounter(Expression<Func<T, TResult>> function)
    {
        Action action = () => _calls++;
        Expression<Action> closurExpression = () => action();
        var result = Expression.Block(closurExpression, function);
        _functionWithInjection = Expression.Lambda<Func<T,TResult>>(result).Compile();
    }
var rw = new RecursiveFunctionWithCounter<int, int>(
        (n, self) => { return n < 2 ? 1 : n * self[n - 1]; }
);

int rr = rw[3]; // rr=6
int rc = rw.Calls; // rc=3
var rw=带计数器的新递归函数(
(n,self)=>{returnn<2?1:n*self[n-1];}
);
int rr=rw[3];//rr=6
int rc=rw.Calls;//rc=3

另一方面,如果您真正想要做的是在代码中检测一些现有的方法,那么请考虑做一点(例如,这是在每个方法调用上增加性能计数器的一个方面)。通过这种方式,您只需在方法中添加一个属性,如
IncrementPerformanceCounterAttribute
,AOT库就会完成其余的工作。

您实际上想要实现什么?我已经给出了一个答案,但实际上这是一个绕过编译器的确切规则,同时仍然违反这些规则精神的例子。你到底想达到什么目的?我已经给出了一个答案,但它实际上是绕过编译器的确切规则,同时仍然违反这些规则的精神。至少,它是有效的(与我的解决方案不同)。如果不考虑性能,这是非常好的。关于AOP的内容:我不想对外部代码使用任何属性,所有事情都应该在这个类的内部完成。对于用户来说,除了附加的字段调用和
foo[x]
concept而不是
foo(x)
,它不应该与简单的委托不同。也许,Rosylin后处理可以帮助我,但它没有做到至少,它是有效的(不像我的解决方案)。如果不考虑性能,这是非常好的。关于AOP的内容:我不想对外部代码使用任何属性,所有事情都应该在这个类的内部完成。对于用户来说,除了附加的字段调用和
foo[x]
concept而不是
foo(x)
,它不应该与简单的委托不同。也许,Rosylin后处理可以帮我,但它还没有完成