[英]Expression trees - unnecessary conversion to int32
表達式樹在處理字節和短路時似乎構建了不必要的轉換,它們將雙方(例如二進制表達式)轉換為int32。
這是我見過的一些Linq提供程序中的一個問題,每個都必須剝離這個冗余層才能獲得原始表達式。 (NHibernate不會刪除此層並在SQL查詢中創建可怕的CAST)。
// no conversion
Console.WriteLine((Expression<Func<int, int, bool>>) ((s, s1) => s == s1));
// converts to int32
Console.WriteLine((Expression<Func<short, short, bool>>) ((s, s1) => s == s1));
// converts to int32
Console.WriteLine((Expression<Func<byte, byte, bool>>) ((s, s1) => s == s1));
如果您嘗試構建一個能夠進行精確比較的表達式(沒有轉換),那么您將獲得成功。
所以問題是,這種行為的原因是什么?
EDIT .net 4.0 64bit,同樣適用於4.5 64bit
這真的很有趣; 遺憾的是,表達式樹編譯器的規則沒有正式指定 - 規范中有一個簡短的“在其他地方”,但是:它們並不是真的。
如果它導致問題,你可以嘗試發現並刪除它 - 如下所示,這是100%未經測試和使用自己風險等:
static void Main()
{
Console.WriteLine(((Expression<Func<short, short, bool>>)((s, s1) => s == s1)).Unmunge());
Console.WriteLine(((Expression<Func<byte, byte, bool>>)((s, s1) => s == s1)).Unmunge());
}
static Expression<T> Unmunge<T>(this Expression<T> expression)
{
return (Expression<T>)RedundantConversionVisitor.Default.Visit(expression);
}
class RedundantConversionVisitor : ExpressionVisitor
{
private RedundantConversionVisitor() { }
public static readonly RedundantConversionVisitor Default = new RedundantConversionVisitor();
protected override Expression VisitBinary(BinaryExpression node)
{
if(node.Type == typeof(bool) && node.Method == null
&& node.Left.NodeType == ExpressionType.Convert && node.Right.NodeType == ExpressionType.Convert
&& node.Left.Type == node.Right.Type)
{
UnaryExpression lhs = (UnaryExpression)node.Left, rhs = (UnaryExpression)node.Right;
if (lhs.Method == null && rhs.Method == null && lhs.Operand.Type == rhs.Operand.Type)
{
// work directly on the inner values
return Expression.MakeBinary(node.NodeType, lhs.Operand, rhs.Operand, node.IsLiftedToNull, node.Method);
}
}
return base.VisitBinary(node);
}
}
輸出之前:
(s, s1) => (Convert(s) == Convert(s1))
(s, s1) => (Convert(s) == Convert(s1))
輸出后:
(s, s1) => (s == s1)
(s, s1) => (s == s1)
回答你的問題:
為什么表達式樹在處理字節和短路時似乎構建了不必要的轉換...所以問題是,這種行為的原因是什么?
答案隱藏在這樣的事實中:C#類型為short
, ushort
, byte
和sbyte
缺少算術,比較......運算符 :
提取: 4.1.5整數類型
對於二進制+, - ,*,/,%,&,^,|,==,!=,>,<,> =和<=運算符,操作數轉換為類型
T
,其中T
是第一個int
,uint
,long
和ulong
,可以完全表示兩個操作數的所有可能值。 然后使用類型T
的精度執行操作,結果的類型是T
(或關系運算符的bool)。 不允許一個操作數為long類型,另一個操作數為double類型的二元運算符。
7.9.1整數比較運算符描述了可用的運算符及其操作數
bool operator ==(int x, int y);
bool operator ==(uint x, uint y);
bool operator ==(long x, long y);
bool operator ==(ulong x, ulong y);
... // other operators, only for int, uint, long, ulong
轉換是由Compiler為您完成的(您在沒有顯式轉換的情況下成功構建轉換的原因)
因為沒有運營商使用短...所以必須應用轉換。 當然,它后來依賴於LINQ提供程序,如何將這種“表達式”轉換為SQL。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.