2012-11-26 29 views
4

我仍然用OO和C#讓自己的腳變得溼潤。我相信這是一個簡單的問題,我想我知道答案,但我想確定。在C中傳遞派生對象的集合#

如果我有一個叫Car類和一個名爲Ford另一類來自Car繼承,卻又叫Mustang另一類從Ford類繼承。

是否可以接受/可能創建一個接受Car對象的集合,然後當我認爲這種方法實際上傳遞給方法的Mustang(或Ford)對象的集合,因爲他們實際上是Car對象的方法?

我的想法是,這應該是可能的,理解我只能訪問Car類的Properties \ Methods。我是否基於此?

而且,如果我是正確的,你可以這樣做:你需要的Mustang集合轉換爲Car集合中的調用方法?

回答

3

不,這是不可能的。

所以,如果我們有一個函數,接受List<Car>類型。很明顯,該功能應該能夠將Prius添加到該列表中,否?那麼,如果你被允許通過List<Mustang>這種方法,你剛剛添加PriusList<Mustang>,顯然這將是不好的。

現在如果不是通過List,該方法的參數爲IEnumerable或某個其他只讀集合類型之一,那麼它可能是「協變」的。在這種情況下,例如,您可以接受一個IEnumerable<Car>並將其傳遞給List<Mustang>,因爲您從不添加到列表中,只能訪問各種元素,並且只要所有的Mustang對象都是Car對象即不是問題。

設計也似乎有點......關閉。我不認爲Ford應該從Car繼承。 Ford不是一輛汽車,它是一個品牌,一家公司,一種汽車。 Mustang是一輛汽車,所以它從一個繼承是有意義的。我會創建一個新類型,例如Manufacturer,其中您可以創建FordToyota等,並使該(只讀)屬性爲Car

+0

我不確定我是否理解你的答案,但是如果'Prius'繼承自'Car',並且'Mustang'繼承自'Car',那麼你就可以添加一個'Prius'或'Mustang'一個'Car'類型的列表。 – Matthew

+0

@Matthew是的,你應該,可以。但是,如果您將一個'List '傳遞給一個參數爲'List '的方法,那麼您可以爲其添加一個'Prius',因此最終結果是一個帶有'Prius'的List 。那會很糟糕。但是,你**不能**將'List '傳遞給接受'List '的方法。這只是解釋原因。 – Servy

+0

也許我的問題最好像這樣......我想創建一個方法來接受一個基本類型的對象(汽車)的集合...我不在乎它是什麼類型的汽車......我只是希望它接受類型爲Car(Mustang,Prius,Corvette等)的物品清單。然後在我的方法中,我可以一般地處理每輛車,但也能分辨出它是哪種類型的車,所以如果它實際上是普銳斯,我可以告訴它做其他事情。合理? – BMT

1

如果您只打算訪問Car課程中的方法和屬性,則沒有理由通過Mustangs的列表。相反,你應該只處理你的Mustangs,就好像它們是Cars一樣。這是繼承的重點之一。您可以簡單地創建一個類型車列表List<Car>,然後添加您的Mustangs它。然後通過類型Car的列表。這是更可擴展的,因爲它可以接受從Car繼承的任何對象,並且由於您只使用來自Car的屬性/方法,所以它與您需要的定義一樣嚴格。

如果您需要Mustang類中的特定行爲,但調用該行爲的通用接口定義Car中的方法,請在Mustang中覆蓋該方法。再說一遍,這是更具擴展性的,因爲當你創建一個NineEleven類時,你也可以重寫這個方法,從而給你在子類中的不同行爲,而不實際暴露它們的類型。

+0

總是假設他想擁有汽車列表而不是某種派生類型的列表是不對的。通常有一個更多派生類型的集合是有意義的。 – Servy

+0

@Servy是的,但是如果嚴格遵守派生類型,那麼您應該有一個嚴格適用於派生類型的方法,或者應該調用派生類型中重載的方法。 – evanmcdonnal

+0

同樣,我不同意。如果你有一個派生類型的集合,你不應該*只需要將它傳遞給一個接受派生類型集合的方法,至少在概念上是這樣。在實踐中你可以做什麼是有限制的。這裏的基本概念是「協變」,C#已經實現了它(在一定程度上)。 – Servy

0

你可以做到這一點,傳遞一個List<Car>含有Ford:■例如:

public void Test() 
{ 
    // This works: 
    var fords = new List<Car> {new Ford()}; 
    FixCars(fords); 

    // This does not work (since you cannot pass non car-typed list): 
    // var mustangs = new List<Ford> {new Ford()}; 
    // FixCars(fords); 
} 

public void FixCars(List<Car> cars) 
{ 
    // Do stuff, for example check actual type and do specialized things: 
    foreach (var car in cars) 
    { 
     var ford = car as Ford; 
     if (ford != null) 
      ford.Honk(); 
    } 
} 

public class Car 
{  
} 

public class Ford : Car 
{ 
    public void Honk() {} 
} 
+0

現在看看當您嘗試在'List '上調用'FixCars'時會發生什麼。你會看到它不起作用。這是爲什麼? (這基本上是OP要求的問題。) – Servy

+0

@Servy但他在這裏顯示'List '。 – SimpleVar

+0

@YoryeNathan來自OP:'「當我打電話給那個方法時,實際上傳遞給了那個方法一個Mustang集合」' – Servy

1

其他人已經解釋發送野馬的集合作爲參數,以不同的方法的各個方面,那麼我只需添加一些你可能會覺得有用的信息。

如果你有汽車的集合List<Car>你可以得到的只有野馬出來的:

IEnumerable<Mustang> mstngs = cars.OfType<Mustang>(); 
List<Mustang> mstngsLst = mstngs.ToList(); 

如果你有野馬的集合List<Mustang>你可以投他們都到汽車行駛:

IEnumerable<Car> cars = mstngs.Cast<Car>(); 
List<Car> carsLst = cars.ToList(); 

順便說一句,轉換回列表並不是必須的。這取決於你需要做什麼與收集。