2015-05-29 70 views
0

我很難覆蓋可變參數函數。例子不是話值得更好,讓我們舉個例子:覆蓋可變參數函數

這裏是我的抽象類:

public abstract class MyClass<T> { 
    public abstract T DoSomething(params Object[] objs); 
    public void ShowSomething(List<T> items){ 
     foreach(T it in items){ 
      Console.WriteLine(string.Format("{0},{1},{2}",it.propA,it.propB,it.propC)); 
     } 
    } 
    // Other things 
} 

這是我的企圖重寫它:

public class MyOverridenClass : MyClass<MyType> { 
    public override MyType DoSomething(int a, int b, string c){ 
     return new MyType(){ propA = a+b, propB = a-b, propC = c+""+a}; 
    } 
} 

而且從我的主:

public static void Main(string[] args){ 
    MyOverridenClass cl = new MyOverridenClass(); 
    List<MyType> lst = new List<MyType>(); 
    lst.Add(cl.DoSomething(1,2,"foo")); 
    cl.ShowSomething(); 
} 

我期望輸出:

3,-1,foo1 

但是,當我編譯時,我有一個錯誤,說沒有找到合適的方法重寫DoSomething(int,int,string)。

這是甚至可能或我必須找到解決方法嗎?

謝謝!

回答

1

DoSomethingMyOverriddenClass不能覆蓋DoSomething(params Object[] objs),因爲你不能覆蓋使用非可變參數之一的可變參數函數。

爲什麼不這樣做的微不足道的答案是因爲規範說的那樣。但是在一個不是C#的想象中的語言中,這仍然行不通,因爲實現方法不如基本方法具體,違反合同。

在C#中,簽名必須在重寫時完全匹配,但這不是正確性所必需的。爲了正確性,方法實施合同就足夠了。

例如,這是一個基類,它返回Base類型的內容,並將一個對象作爲參數。

public class Base { 
    public Base example(TParam obj) 
} 

如果我們覆蓋的例子,我們需要的是更具體的是正確的

public class Derived : Base { 
    override public TReturn example(TParam2 obj) //this is illegal in C# 
} 

C#需要TReturn == BaseTParam == TParam2。同時,正確性要求不太嚴格。它只要求TReturn : Base,那TParam : TParam2(注意它們翻轉)

想知道爲什麼,採取例如

Base b = new Derived() 
Base newbase = d.example(default(TParam)) 

必須返回Base將「適合」的值。它也大多采用任何可以輸入到Base.example的參數。如果它需要更多特定的參數,那麼你就會崩潰,因爲編譯器不知道(並且不知道不應該知道b的類型是Derived

現在回到各種各樣的方法。可以想象,一些不是C#的語言,但它看起來確實允許這樣做。這只是因爲可以想象,這樣是不是C#它有一些語法糖分解可變參數方法,下面就可以convered來回語言:

public T Example(params object[] objs) 

public T Example2(object obj1, object obj2) 

,但在派生類的實現應該總是不太具體的在它的參數列表中,不是更具體。所以最好這個(非C#)語言可以做的是讓你覆蓋,例如,

public T Example(params SpecificType[] values) 

public T Example(params object[] objs) 

public T Example2(object obj1, object obj2) 

,但從來沒有周圍的其他方法。

TL;博士:

語言不允許這樣做,不能讓這個,因爲它會破壞替換原則。

+0

非常好的解釋!謝謝 :) – Kobz

3

當您覆蓋方法時,簽名必須相同。你不能「發明」一個新的簽名。

public override MyType DoSomething(params Object[] objs) 
{ 
    // do something 
} 

沒有什麼,你可以在這裏做...

所以,你必須決定你想要你的方法有什麼簽名,並使用它。你甚至可以保持雙方簽名的MyClass<T>