2010-10-25 54 views
0

我正在編寫一些代碼來幫助簡化表達式樹中的C#方法模式。在使用塊的情況下,有三種方法來使用它::有沒有辦法發現ParameterExpression是否被BlockExpression或LambdaExpression捕獲

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,因爲我無法知道disposible變量是否已經綁定到表達式樹中的其他位置。任何人都可以提出一種方法來確定​​是否被綁定?

+0

如果您處理案例2,您的代碼將會如何不同?看起來它已經是案例2. – Gabe 2010-10-25 14:47:57

+0

現在我假設,如果你不使用參數'toAssign',那麼你的情況是3.如果你使用參數,你的情況是1.案例2會如果你使用了參數,會發生,但'disposible'已經綁定。 – 2010-10-25 14:50:40

+0

你能舉一個你如何使用鍋爐板方法的例子嗎? – Les 2010-10-25 20:13:55

回答

0

您所創建的變量toDispose(作爲使用例如東西)兩三種情況,但只有你一個案件實際上聲明變量(案例#1)。另外兩種情況則假設變量已經在其他地方聲明過了。那麼,您是否可以讓設置爲您的GenerateUsingBoilerPlate方法的一個參數,然後如果它爲空,則創建以表示

這不會回答你關於如何確定disposible變量已經綁定的問題,但你能不能簡單地假設/要求它的約束?然後案例#1和案例#2工作。案例#3不使用可處置,而是使用來表示

編輯
。換句話說,你不需要知道disposible必然,而不是你需要它的約束(如果提供)。如果沒有提供,那麼您需要提供至配置

+0

如何使用toDispose然後如果它的null?它會拋出一個參數爲空的異常。 – 2010-10-25 16:23:02

+0

如果toDispose作爲null傳入,則爲該變量創建自己的本地表達式並分配它。如果它不是空表達式,則假定它是綁定的。如果在表達式運行時,toDispose爲null,那麼讓它拋出一個異常。 – Les 2010-10-25 20:19:08

+0

那麼它的絕對無用,如果它null你如何使用它?它是如何處置的?我不確定這會起作用。 – 2010-10-25 21:36:09

0

實際上有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 
} 

我建議你看一看在Expression.CatchBlock(...)方法,並瞭解參數傳遞給它。 捕獲語句是相似的,因爲聲明本地變量在語句中使用。這可能意味着你的UsingBoilerPlate可能看起來更像這個...

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); } 

爲了處理各4種情景,你會這樣稱呼它?

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()(); 

下一個示例使用一個小竅門,其中using(w)相當於using(w = w)

var action3 = 
    Expression.Lambda<Action> 
    (
     Expression.Block 
     (
      new [] { localVariable }, 
      new Expression[] { 
       Expression.Assign(localVariable, disposeExpression); 
       Using 
       (
        localVariable, 
        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 
       ) 
      } 
     ) 
    ); 
action3.Compile()(); 

而在去年,

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

所以,你不能真正弄明白如果ParameterExpression是綁定在你的方法外部,但你可以告訴你的方法是否是。

相關問題