2009-06-09 24 views
7

我不知道我在做什麼錯在這裏。我有一個泛型類,這基本上是一個榮耀的整數,對於某些字符串格式化的幾種方法,以及進/出字符串和int轉換:在C#中繼承隱含/顯式轉換方法嗎?

public class Base 
{ 
    protected int m_value; 
    ... 
    // From int 
    public static implicit operator Base(int Value) 
    { 
     return new Base(Value); 
    } 
    ... 
    // To string 
    public static explicit operator string(Base Value) 
    { 
     return String.Format("${0:X6}", (int)Value); 
    } 
} 

它的功能正常。我可以成功地使用隱性和顯性的轉換:

Base b = 1; 
Console.WriteLine((string)b); // Outputs "$000001", as expected. 

然後我從這個類派生的,不同的子類,打開/關閉不同的命名位m_value。例如:

public class Derived : Base 
{ 

} 

然後,我不能用我的隱含/從int轉換:

Derived d = 3; 
// Cannot implicitly convert type 'int' to 'Derived'. An explicit conversion exists (are you missing a cast?) 

即使這給了同樣的錯誤:

Derived d = (int)3; 

是隱式/顯式轉換沒有在派生類中繼承?如果不是,這將需要大量的代碼複製。

回覆 非常感謝您的快速響應!你們都應該得到'答案'選中標記,他們都是非常好的答案。關鍵是要考慮等號兩邊的類型。現在我想這樣想,這很有道理。

我顯然只需要重寫我的「派生」轉換。 「到Int32,字符串等」轉換仍然適用。

+1

想了解更多關於這一切的一些細節,請閱讀我關於這個主題的文章:http://blogs.msdn.com/ericlippert/archive/2007/04/16 /chained-user-defined-explicit-conversions-in-c.aspx – 2009-06-09 15:12:16

回答

6

原因

Derived d = (int)3; 

不起作用是因爲類型Derived不正是運營商Base的返回值,需要調用該運營商相匹配。請注意,您尚未提供任何包含代碼new Derived(...)的轉換運算符,因此您無法通過這種方式創建新的Derived實例並不奇怪。

注意,但是,相反的轉換

Derived v = ...; 
string s = (string)v; 

將正常工作(就好像它是「繼承」,雖然這不是真正的繼承由於static關鍵字)。

+1

我不認爲有任何方法可以獲得OP的期望行爲? – weberc2 2012-11-28 17:28:47

3

不,它不會那樣工作。編譯器不會將隱式地從基地向下傾斜爲您派生。基本上,你不能這樣做......

D d = new B(); 

你會得到你的基類implmentations從串投,因爲它會做的隱含上溯造型爲您服務。

你可以做一個變通,如果你不想你的方法與擴展功能複製到你的派生類的整數,如(假設你的派生類被稱爲d)...

public static class Ext 
{ 
    public static D IntAsD(this int val) 
    { 
     return new D(val); 
    } 
} 

然後,你可以做你想做什麼?

D d1 = 5.IntAsD(); 

當然,它並不完美,但它可能會滿足您的需求。

2

重載操作符(包括轉換)是繼承的,但不是以您看似期望的方式。特別是,它們不會神奇地擴展到派生類型。讓我們來看看你的代碼再次:​​

Derived d = 3; 

此時編譯器有兩個教學班,System.Int32,並派生工作。所以它在這些類中尋找轉換運算符。它會考慮由Derived from Base繼承的那些,即:

public static implicit operator Base(int Value); 
public static explicit operator string(Base Value); 

第二個不匹配,因爲參數應該是Int32。第一個匹配參數,但是它的返回類型是Base,並且不匹配。在另一方面,你可以這樣寫:

string s = (string) new Derived(); 

,它會工作,因爲在基本明確經營者存在且適用(參數預期爲基地,從基地派生繼承,因此參數類型相匹配)。

編譯器不能自動重新定義派生類型中的轉換運算符「正常」的原因是因爲沒有通用的方式來這樣做。

0

不,他們不是。這裏的線索:

public **static** implicit operator Base(int Value)

在C#中的靜態方法只是進入私人類成員的全局函數。他們永遠不會繼承

+3

雖然靜態方法沒有被繼承是正確的,但這與這個問題完全無關。 C#3.0規範的相關部分是6.4節。3,在那裏我們描述了哪些類型被搜索到了靜態操作符:「這個集合由源​​類型及其基類和目標類型及其基類組成」。 – 2009-06-09 15:09:58

1

轉換/操作符方法是一種方便,但正如其他人已經指出的,他們並不總是會做你想做的。特別是,如果編譯器在=符號的兩側都看不到正確的類型,它甚至不會考慮您的轉換/運算符。這就是爲什麼如果你這樣做,你會得到一個編譯器警告:

object str = "hello"; 
if (str == "hello") { 
} 

此外,使用as/is關鍵字時不考慮自定義轉換。

當考慮實現顯式/隱式轉換時,您還應該考慮實現IConvertible和/或實現TypeConverter。當您擁有基類句柄類型轉換時,這給您更多的靈活性。

0

儘管您無法直接執行此操作,但您可以使用一些捷徑來啓用代碼重用。

public class Base 
{ 
    protected int m_value; 
    ... 
    // From int 
    public static implicit operator Base(int Value) 
    { 
     Base newObject = new Base(); 
     newObject.FromInt(Value); 
     return newObject; 
    } 
    ... 
    // To string 
    public static explicit operator string(Base Value) 
    { 
     return String.Format("${0:X6}", (int)Value); 
    } 

    //Instance FromInt() 
    protected void FromInt(int value) 
    { 
     m_value = value; 
    } 
} 

public class Derived : Base 
{ 
    // To string, re-use Base-ToString 
    public static explicit operator string(Derived Value) 
    { 
     // Cast (Derived)Value to (Base)Value and use implemented (Base)toString 
     return (string)(Base)Value; 
    } 

    // Use FromInt, which has access to instance variables 
    public static implicit operator Base(int Value) 
    { 
     // We can't use (Base)obj = Value because it will create 
     // a "new Base()" not a "new Derived()" 
     Derived newObject = new Derived(); 
     newObject.FromInt(Value); 
     return newObject; 
    } 
}