簡體   English   中英

表達式樹 - 不必要的轉換為int32

[英]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#類型為shortushortbytesbyte缺少算術,比較......運算符

提取: 4.1.5整數類型

對於二進制+, - ,*,/,%,&,^,|,==,!=,>,<,> =和<=運算符,操作數轉換為類型T ,其中T是第一個intuintlongulong ,可以完全表示兩個操作數的所有可能值。 然后使用類型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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM