2017-09-15 102 views
4

請考慮下面的MyDecimal類。在C#,我們可以歸功於其轉換爲整數隱式decimal操作:在表達式樹中顯式強制轉換?

int i = (int)new MyDecimal(123m); 

如何在表達式樹產生的等效代碼?

當使用Expression.Convert.NET 4.5.1)時,立即失敗,出現No coercion operator is defined between types 'System.Int32' and 'MyDecimal'。它似乎只考慮隱式演員操作。

try 
{ 
    var param = Expression.Parameter(typeof(int), null); 
    var convert = Expression.Convert(param, typeof(MyDecimal)); 
} 
catch (Exception ex) 
{ 
} 

MyDecimal類:

Expression<Func<MyDecimal,int>> convert = m => (int)m; 

使用的工具鏈接LinqPad我們可以檢查:

public class MyDecimal 
{ 
    private readonly decimal value; 

    public MyDecimal(decimal value) 
    { 
     this.value = value; 
    } 

    public static implicit operator decimal(MyDecimal myDecimal) 
    { 
     return myDecimal.value; 
    } 

    public static implicit operator MyDecimal(decimal value) 
    { 
     return new MyDecimal(value); 
    } 
} 
+1

'趕上(例外){}' - 請,請,不這樣做。 – Heinzi

+0

@ Heinzi - 是catch(Exception){}'any better <):O) –

+0

我認爲@Heinzi的意思是你應該記錄異常的細節:例如catch(Exception ex){Console.Write(ex); }'。 –

回答

4

它總是有趣的例子,做同樣的事情表達式的lambda表達式樹轉換並看到我們有以下內容:

Expression<Func<MyDecimal,int>> (type: Lambda) 
| 
+- UnaryExpression (type:Convert) - Convert(int, decimal) 
    | 
    +- UnaryExpression (type:Convert) - Convert(decmal, MyDecimal) 

所以,雖然編譯允許從decimalint隱式轉換,你可以看到,相當於Lambda要求轉化爲明確的。

編輯

因此,構建完整的表達,你有這樣的:

 Expression.Assign(
      Expression.Variable(typeof(int), "i"), 
      Expression.Convert(
       Expression.Convert(
        Expression.New(
         typeof(MyDecimal).GetConstructor(new[] {typeof(decimal)}), 
         Expression.Convert(
          Expression.Constant(1), 
          typeof(decimal) 
         ) 
        ), 
        typeof(decimal)), 
       typeof(int) 
      ) 
     ) 

幾點需要注意:

  • 我們正在轉換int 1到decimal傳遞給構造函數
  • 我們必須查看具有正確類型參數的構造函數(我在作弊並假設它是公開的)
  • 我們假設i已經聲明。
+0

使用兩個'Expression.Convert'解決類型已知爲'typeof(int)'的問題。我想知道你的代碼是否可以改進來處理任意的'Type'對象。例如。 '輸入t = myObj.GetType()'其中'myObj'可以是'int'或'decimal'。 – l33t

+0

@ l33t - 這肯定是一個不同的問題?您可能需要檢查.Net Base Type的有效轉換,然後從那裏進行轉換。瞭解您打算如何在更廣泛的背景下使用此代碼可能會有幫助,因爲可能有更簡單的解決方案。 –

+1

@ l33t - 同樣,看看'IConvertible'接口(https://msdn.microsoft.com/en-us/library/system.iconvertible(v=vs.110).aspx)和'Convert.ChangeType'( https://msdn.microsoft.com/en-us/library/system.convert(v=vs.110).aspx) - 它們有可能簡化整個過程。 –

0

我做了一些改變,希望大家喜歡我的做法:

class Program 
{ 
    static void Main(string[] args) 
    { 
     MyDecimal myDecimal = new MyDecimal(123.123m); 
     myDecimal = 123.123m; 
     int i = (int)myDecimal; 
     i = myDecimal.ToInt(); 
     i = myDecimal.ToIntExpression(); 
    } 


    public class MyDecimal 
    { 
     private readonly decimal value; 

     public MyDecimal(decimal value) 
     { 
      this.value = value; 
     } 

     public static implicit operator decimal(MyDecimal myDecimal) 
     { 
      return myDecimal.value; 
     } 

     public static implicit operator MyDecimal(decimal value) 
     { 
      return new MyDecimal(value); 
     } 

     public int ToInt() 
     { 
      return Convert.ToInt32(this.value); 
     } 

     public int ToIntExpression() 
     { 
      return Convert.ToInt32(Expression.Constant(this.value, typeof(decimal)).Value); 
     } 
    } 

}