Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 有没有办法发现ParameterExpression是由BlockExpression还是LambdaExpression捕获的_C#_Expression - Fatal编程技术网

C# 有没有办法发现ParameterExpression是由BlockExpression还是LambdaExpression捕获的

C# 有没有办法发现ParameterExpression是由BlockExpression还是LambdaExpression捕获的,c#,expression,C#,Expression,我正在编写一些代码来帮助简化表达式树中的C方法模式。在使用块的情况下,有三种使用方法: using(var something=IDisposible_value) //1 using(something = IDisposible_value) //2 using(something) //3 现在,我的代码如下所示: public static Expression GenerateUsingBoilerPlate(ParameterExpressi

我正在编写一些代码来帮助简化表达式树中的C方法模式。在使用块的情况下,有三种使用方法:

using(var something=IDisposible_value) //1

using(something = IDisposible_value)   //2

using(something)                 //3
现在,我的代码如下所示:

public static Expression GenerateUsingBoilerPlate(ParameterExpression disposible,Expression toAssign,Expression body)
{
    ArgumentValidator.AssertIsNotNull(() => disposible);
 ArgumentValidator.AssertIsNotNull(() => body);

    var toDispose = Expression.Variable(typeof(IDisposable));
    Expression retVal = Expression.TryFinally(
        body,
        Expression.Block(
            new[] { toDispose },
            Expression.Assign(
                toDispose,
                Expression.TypeAs(
                    disposible,
                    typeof(IDisposable)
                )
            ),
            Expression.IfThen(
                Expression.NotEqual(
                    toDispose,
                    Expression.Default(
                        typeof(IDisposable)
                    )
                ),
                Expression.Call(
                    toDispose, 
                    "Dispose", 
                    Type.EmptyTypes
                )
            )
        )
    );
    if (toAssign != null)
    {
        retVal = Expression.Block(
            new[] { disposible },
            Expression.Assign(
                disposible ,
                toAssign
            ),
            retVal
        );
    }
    return retVal;
}

问题是这段代码只能处理案例1和案例3,因为我无法知道可处置变量是否已绑定到表达式树中的其他位置。有人能提出一种方法来确定ParameterExpression是否已绑定吗?

您正在为三种情况中的两种情况创建一个变量,以在使用示例中用作某种东西,但实际上只有一种情况声明了变量case1。其他两种情况假设变量已经在其他地方声明。那么,能否将toDispose设置为GenerateUsingBoilerPlate方法的一个参数,如果为null,则创建toDispose

这并不能回答您关于如何确定可处置变量是否已绑定的问题,但您能否不简单地假设/要求它已绑定?然后案例1和案例2起作用。案例3没有使用disposible,而是使用Dispose

编辑
换句话说,您不需要知道disposible是否绑定,相反,如果提供了disposible,您需要绑定它。如果未提供,则需要提供toDispose。

调用using实际上有4种不同的方法。下面的示例和数字大致与您的数字对应,除了我添加了4

using (var a = File.CreateText(@"c:\temp\test.txt"))  //#1
{
    // a is only visible in this context
}
TextWriter w;
using(w = File.CreateText(@"c:\temp\test.txt")) //#2
{
    // w is visible outside of this context, but is only valid within the context
}
w = File.CreateText(@"c:\temp\test.txt");
using (w)                                       //#3
{
    // w is visible outside of this context, but is only valid between assignment and end of this context
}
using (File.CreateText(@"c:\temp\test.txt"))    //#4
{
    // the disposable is not visible in any context
}
我建议你看看表达式。CatchBlock。。。方法,并查看参数是如何传递给它的。catch语句的相似之处在于声明了要在语句中使用的局部变量。这可能意味着你使用的样板可能更像这样

public static Expression<Action> UsingBoilerPlate(
                 Expression disposeExpression,
                 Expression bodyExpression,
                 ParameterExpression localVariable,
                 bool unbound) { ... }
public static Expression<Action> UsingBoilerPlate(
                 Expression disposeExpression,
                 Expression bodyExpression,
                 ParameterExpression localVariable)
{  return UsingBoilerPlate(disposeExpression, bodyExpression, localVariable, true); }
public static Expression<Action> UsingBoilerPlate(
                 Expression disposeExpression,
                 Expression bodyExpression)
{  return UsingBoilerPlate(disposeExpression, bodyExpression, null); }
var action1 =
    Expression.Lambda<Action>
    (
        Using
        (
            disposableExpression,
            bodyExpression,
            localVariable
        )
    );
action1.Compile()();

var action2 =
    Expression.Lambda<Action>
    (
        Expression.Block
        (
            new [] { localVariable },
            new Expression[] {
                Using
                (
                    disposableExpression,
                    bodyExpression,
                    localVariable,
                    false
                ),
                Expression.IfThenElse(
                    Expression.NotEqual(
                        localVariable, Expression.Constant(null)),
                    ((Expression<Action>)(() => Console.WriteLine("w is NOT null"))).Body,
                    ((Expression<Action>)(() => Console.WriteLine("w is null"))).Body
                )
            }
        )
    );
action2.Compile()();
最后,

var action4 =
    Expression.Lambda<Action>
    (
        Using
        (
            disposableExpression,
            bodyExpression
        )
    );
action4.Compile()();

因此,您无法真正确定ParameterExpression是否绑定到您的方法外部,但您可以告诉您的方法它是否绑定到外部。

如果处理案例2,您的代码看起来会有什么不同?现在我假设如果你不使用参数来赋值,那么你就是在案例3中。如果您确实使用了案例1中的参数。如果您使用参数,则会出现第二种情况,但disposible已绑定。您能否举例说明如何使用boiler-plate方法?foreach循环是我当前唯一的示例。IEnumerator是IDisposable的,因为我已经在构建循环,因为我提取了using语句。因此,我的foreach的主体读取::return Expression.Block new[]{currentVariable},ExpressionHelper.GenerateUsingBoilerPlate枚举器,getEnumeratorCall,ExpressionHelper.GenerateWhileLoopBoilerPlate moveNextExpression,Expression.Block assignCurrent,body,@break我有点明白你在做什么。此时是否将'enumerator'ParameterExpression作为参数传递给您?或者您正在创建“枚举器”?如果它为空,如何使用来显示?它将引发参数null异常。如果toDispose作为null传入,则为该变量创建自己的局部表达式并赋值。如果它不是空表达式,则假定它是绑定的。如果在表达式运行时,toDispose为null,那么就让它抛出一个异常。如果它为null,那么它是完全无用的。您如何使用它?它是如何处理的?我不确定这是否有效。我不认为这是无用的,但我也不认为我们沟通得很好。所以忽略这个答案,看看我的下一个答案。
var action4 =
    Expression.Lambda<Action>
    (
        Using
        (
            disposableExpression,
            bodyExpression
        )
    );
action4.Compile()();