2011-02-25 56 views
1

我有一個LambdaExpression,它將一個對象作爲參數並最終返​​回一個對象。 出於測試的目的,這裏是一個Lambda(創建longhand以匹配我真正傳入的內容),它返回一個DateTime作爲對象裝箱。 爲了達到此目的,LambdaExpression需要一個XmlNode並返回一個對象。 它必須返回一個對象,真正的返回類型可能是以下任何一種:DateTime,bool,int,decimal,XmlDocument [到目前爲止] 一般的想法是,在解析器深處,創建這個lambda,並提取一個值從它的輸入參數並返回它鍵入,但盒裝在一個對象。Expression.LessThan vs LambdaExpression <Func <ParamType,object >>

 XmlNode node = null; 
     ParameterExpression instanceExpression = Expression.Parameter(typeof(DynamicNode), "instance"); 
     ParameterExpression result = Expression.Parameter(typeof(object), "result"); 
     LabelTarget blockReturnLabel = Expression.Label(typeof(object)); 
     BlockExpression block = Expression.Block(
          typeof(object), 
          new[] { result }, 
          Expression.Assign(result, Expression.Convert(Expression.Constant(DateTime.Now.AddSeconds(-1)), typeof(object))), 
          Expression.Return(blockReturnLabel, result), 
          Expression.Label(blockReturnLabel, Expression.Constant(-2, typeof(object)))); 
LambdaExpression lax = Expression.Lambda<Func<XmlNode, object>>(block, instanceExpression); 

稍後在代碼中,我們正在評估<,< =,>,> =,==和!=,所以我們希望這個LambdaExpression結果

通常比較另一種表達方式,我們可以假設LambdaExpression位於右側的Expression.LessThan 的左側,可能幾乎是任何表達式,但讓我們假設它是鍵入的。 這意味着它可以是ConstantExpression或類似的...但它有一個類型。

這意味着Expression.LessThan [例如]失敗,因爲當它調用Expression.Invoke時,LambdaExpression返回一個對象,而RHS是任何類型。

假設從LambdaExpression返回的對象內裝入的類型實際上與右側的類型相當;例如

(object)5 < 6 

如何編寫表達式,可以將盒裝類型與非盒裝類型進行比較而不會崩潰? 我試過linqpad中的各種排列,包括試圖在普通的c#中寫這個 - 即沒有表達式,只是嵌套if-then-else但是我無法讓這個工作很正確。 通常情況下,我可能會寫這樣的事:

/* 
int i = 3; 
object o = (object)i; 
int compare = 4; 
*/ 
DateTime dt = DateTime.Now; 
object o = (object)dt; 
DateTime compare = DateTime.Now.AddSeconds(1); 

bool b = false; 
if(o.GetType().IsAssignableFrom(compare.GetType())) 
{ 
    if(o is int) 
    { 
     b = (int)o < (int)(object)compare; 
    } 
    if(o is DateTime) 
    { 
     b = (DateTime)o < (DateTime)(object)compare; 
    } 
    if(o is decimal) 
    { 
     b = (decimal)o < (decimal)(object)compare; 
    } 
} 
Console.WriteLine(b); 

有了這個,假設O和比較實際上是同一類型,其中一人被裝箱爲對象,我們仍然可以執行<操作.. 。

所以我想我的問題是,當我在左邊有一個LambdaExpression,並且右邊的表達式[如果兩個不是相同的類型,假的結果比碰撞]

希望有人能幫到,

加雷思

回答

1

如何編寫能夠 盒裝類型比較的拆箱 類型沒有崩潰的表情?

您可以對此使用Expression.Unbox方法:「創建一個表示明確拆箱的UnaryExpression。「

讓我們把你的(int)(object)5 < 6例如:

// boxed int 
var left = Expression.Constant(5, typeof(object)); 

// int 
var right = Expression.Constant(6, typeof(int)); 

// More generally, you can use right.Type instead of typeof(int) 
// if its static type is appropriate. 
// Otherwise, you may need to unbox it too. 
var unboxedLeft = Expression.Unbox(left, typeof(int)); 

var lessThanEx = Expression.LessThan(unboxedLeft, right);  
var expression = Expression.Lambda<Func<bool>>(lessThanEx, null); 

// True : (int)(object)5 < 6 
bool b = expression.Compile()(); 

所以我想我的問題是,我怎麼 寫上面的代碼時,我對左側 LambdaExpression,並在 表達[如果兩者不是同一類型,結果比錯誤更好]

在這種情況下,您可以編寫一個條件表達式來檢查盒裝對象的運行時類型與右側類型相同,如果是,則進行拆箱+小於比較,否則返回false。

E.g.

// From earlier 
var left = ... 
var right = ... 
var lessThanEx = ... 

var body = Expression.Condition(Expression.TypeEqual(left, right.Type), 
           lessThanEx, 
           Expression.Constant(false)); 

var expression = Expression.Lambda<Func<bool>>(body, null); 
+0

運作Em..I大概覺得OP喜歡內比較邏輯這樣的表達。 – 2011-02-25 11:45:02

+0

好吧,這有助於 - 因此Expression.Condition與Expression.IfThenElse類似,據我所知 - 它是否與Ternary bool更相似? true:false – 2011-02-25 11:46:14

+0

他可能想要一個表達式來比較它們,而不是比較結果,我誤解了。 – 2011-02-25 11:47:03

1

結合我原來的職位與你的球員的答案,這似乎在LinqPad

XmlNode node = null; 
ParameterExpression instanceExpression = Expression.Parameter(typeof(XmlNode), "instance"); 
ParameterExpression result = Expression.Parameter(typeof(object), "result"); 
LabelTarget blockReturnLabel = Expression.Label(typeof(object)); 
BlockExpression block = Expression.Block(
        typeof(object), 
        new[] { result }, 
        //this would normally be a function invoke 
        Expression.Assign(result, Expression.Convert(Expression.Constant(DateTime.Now.AddSeconds(-1)), typeof(object))), 
        Expression.Return(blockReturnLabel, result), 
        Expression.Label(blockReturnLabel, Expression.Constant(-2, typeof(object)))); 
LambdaExpression lax = Expression.Lambda<Func<XmlNode, object>>(block, instanceExpression); 

var left = Expression.Invoke(lax, instanceExpression); 
//false result 
//var right = Expression.Constant(5, typeof(int)); 
//true result 
var right = Expression.Constant(DateTime.Now, typeof(DateTime)); 

var unboxedLeft = Expression.Unbox(left, right.Type); 
var lessThanEx = Expression.LessThan(unboxedLeft, right);  

var body = Expression.Condition(Expression.TypeEqual(left, right.Type), lessThanEx, Expression.Constant(false)); 
var expression = Expression.Lambda<Func<XmlNode, bool>>(body, instanceExpression); 

bool b = expression.Compile()(node); 
Console.WriteLine(b); 
+0

似乎我可以通過表達式樹嘟my,但我無法弄清楚StackOverflow上的代碼塊! – 2011-02-25 11:56:10

+0

只需使用4的縮進。或者,使用0的縮進,選擇代碼,然後點擊代碼示例按鈕,該按鈕看起來像「{}」 – Ani 2011-02-25 11:59:18

相關問題