C# 有没有办法发现ParameterExpression是由BlockExpression还是LambdaExpression捕获的
我正在编写一些代码来帮助简化表达式树中的C方法模式。在使用块的情况下,有三种使用方法: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
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()();