2016-11-15 22 views
3

我有一個類(簡化爲這個問題的目的)是一個包裝了decimal值,並使用幾個implicit operator聲明爲類型和包裹值之間轉換:隱運營商和一個編譯器錯誤

private class DecimalWrapper 
{ 
    public decimal Value { get; private set; } 

    public DecimalWrapper(decimal value) 
    { 
     Value = value; 
    } 

    public static implicit operator decimal(DecimalWrapper a) 
    { 
     return a != null ? a.Value : default(decimal); 
    } 

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

implicit operator慣例在這裏請允許做這樣的事情:

DecimalWrapper d1 = 5; // uses implicit operator DecimalWrapper 
DecimalWrapper d2 = 10; 
var result = d1 * d2; // uses implicit operator decimal 

Assert.IsTrue(result.Equals(50)); 
Assert.IsTrue(result == 50); 

現在,假設有一個重載的構造函數,可以採取一個第二類(再次,簡化的) 10或DecimalWrapper

private class Total 
{ 
    private readonly DecimalWrapper _total; 

    public Total(DecimalWrapper total) 
    { 
     _total = total; 
    } 

    public Total(decimal totalValue) 
    { 
     _total = totalValue; 
    } 
} 

我希望能夠通過傳遞一個整數值,這將被轉換爲十進制實例的Total一個實例:

var total = new Total(5); 

然而,這個結果編譯錯誤:

The call is ambiguous between the following methods or properties: 'Namespace.Total.Total(TypeTests.DecimalWrapper)' and 'Namespace.Total.Total(decimal)'

爲了解決這個問題,你必須刪除implicit operator decimal或指定的值5事實上是一個decimal

var total = new Total(5m); 

這一切都很好,但我不明白爲什麼implicit operator decimal與此有關。那麼發生了什麼?

+0

」甚至在運行時不會執行「---爲什麼要這樣呢?你已經傳遞了一個十進制數,所以不需要轉換 - 'Total(decimal totalValue)'構造函數完全匹配它。 – zerkms

+0

@zerkms - 我已經澄清了我的問題一點點 –

+1

這是相關的,因爲有'Total(DecimalWrapper total)'構造函數和一個隱式轉換'int - > decimal - > DecimalWrapper'。編譯器(在它找不到確切的簽名匹配之後)檢查它在類型轉換後可以實現的構造函數,在這種情況下它們都是。 – zerkms

回答

3

您是否在尋找來自語言規範的引用?

原因與重載解析有關。當您指定int值作爲構造函數參數時,沒有過載被認爲是「最好的」,因爲兩者都需要轉換。該規範沒有考慮兩級轉換不同於一個級別,所以兩個構造函數重載是相互等價的。

由於Blorgbeard noted in the comments,您可以通過刪除其中一個構造函數來輕鬆解決問題。他建議消除DecimalWrapper過載,但由於您的字段類型爲DecimalWrapper,因此我會擺脫decimal過載。這樣做,如果您爲構造函數指定int值,則編譯器將爲您隱式轉換爲decimal,然後DecimalWrapper。如果你爲構造函數指定了一個decimal值,那麼編譯器將隱式地轉換爲DecimalWrapper,這是你的構造函數無論如何都會做的。

當然,解決該問題的另一種方法是將其他構造函數添加到Total類,例如,一個需要int。然後不需要轉換,並且將選擇構造函數。但是這對我來說似乎有點矯枉過正。 「