2009-06-03 26 views
2

此問題是由於嘗試Jon Skeet's回答this question如何在使用泛型的基類上使用foreach?

所以我有以下代碼的基礎上述問題鏈接的問題和答案。

public abstract class DeliveryStrategy { } 
public class ParcelDelivery : DeliveryStrategy { } 
public class ShippingContainer : DeliveryStrategy { } 

public abstract class Order<TDelivery> where TDelivery : DeliveryStrategy 
{ 
    private TDelivery delivery; 

    protected Order(TDelivery delivery) 
    { 
     this.delivery = delivery; 
    } 

    public TDelivery Delivery 
    { 
     get { return delivery; } 
     set { delivery = value; } 
    } 
} 

public class CustomerOrder : Order<ParcelDelivery> 
{ 
    public CustomerOrder() 
     : base(new ParcelDelivery()) 
    { } 
} 

public class OverseasOrder : Order<ShippingContainer> 
{ 
    public OverseasOrder() : base(new ShippingContainer()) 
    { 

    } 
} 

我試圖瞭解更多的仿製藥來提高我的技能,所以我的問題: 現在我怎樣才能通過「訂單」的集合使用的foreach循環?我正在使用C#2.0。

代碼示例我正在嘗試做什麼(不編譯)。

List<Order> orders = new List<Order>(); 

orders.Add(new CustomerOrder()); 
orders.Add(new CustomerOrder()); 
orders.Add(new OverseasOrder()); 
orders.Add(new OverseasOrder()); 

foreach (Order order in orders) 
{ 
    order.Delivery.ToString(); 
} 

編輯:添加OverseasOrder給一個更好的例子。

+0

只是出於好奇...你得到的編譯器錯誤是什麼? – 2009-06-03 14:34:53

+0

使用泛型類型'WindowsApplication34.Order '需要'1'類型參數 – Crispy 2009-06-03 14:43:39

回答

6

這裏的問題是訂單是一個通用類,所以Order<T>Order基本上是兩種不同的類型。

你可以這樣做:

public abstract class Order 
{ 
    public abstract String GetDeliveryMethod(); 
} 

public abstract class Order<TDelivery> : Order 
    where TDelivery : DeliveryStrategy 
{ 
    .... the rest of your class 

    public override String GetDeliveryMethod() 
    { 
     return Delivery.ToString(); 
    } 
} 

或者......你可以重新定義爲了不通用的,在這種情況下,你會寬鬆一些強類型。

+1

這通常只是一個好習慣 - 我從未後悔爲泛型類創建非泛型基礎。 – 2009-06-03 14:40:02

2

通用是你要去哪裏錯了。由於泛型的類型是在編譯時編譯的,因此您需要指出您使用哪種類型的命令創建列表。

如果添加類型,這樣它會編譯:

List<Order<ParcelDelivery>> orders = new List<Order<ParcelDelivery>>(); 

     orders.Add(new CustomerOrder()); 
     orders.Add(new CustomerOrder()); 
     orders.Add(new CustomerOrder()); 
     orders.Add(new CustomerOrder()); 
     orders.Add(new CustomerOrder()); 

     foreach (Order<ParcelDelivery> order in orders) 
     { 
      order.Delivery.ToString(); 
     } 

這也許不再是您的本意,但你必須去了解它以不同的方式,如果你需要可以設置這沒有預先確定的類型。

+0

我更新了我的問題。我有兩種不同的訂單。一個使用ParcelDelivery,一個使用ShippingContainer。所以我不能在foreach語句中使用。 – Crispy 2009-06-03 14:51:44

1

但是您沒有任何Order班......您有Order<T>班。 這就是爲什麼你不能有List<Order>類。

如果你想對所有訂單的基類,你現在可以在列表中使用,你應該試試這種方法:

public abstract class OrderBase{ ... } 
... 
public abstract class Order<TDelivery>:OrderBase where TDelivery : DeliveryStrategy { ... } 
0

要迭代,你可以使用這樣的順序...

orders.ForEach(delegate(Order orderItem) { // so so processing });

如果你不想使用匿名方法,那麼寫一個方法,這樣做。

2

在你的情況下,沒有訂單類的東西,只有一個訂單<TDelivery>類。

如果您希望在不知道任何特定子類型(或通用參數)的情況下對訂單進行一般性處理,則需要將您需要的內容抽象到基類或接口中,並使用新訂單類。

abstract class Order { 
    public abstract string DeliveryString(); 
} 

abstract class Order<TDelivery> : Order { 
    // methods omitted for brevity 

    public override string DeliveryString() { 
     return Delivery.ToString(); 
    } 
} 
1

List<Order>不是有效的類型,因爲Order是不是有效的類型 - 你需要一個Order<T>。除非你不知道T.

兩種可能性:

選項1:包裝你foreach泛型方法裏面:

public void WriteOrders<T>(IList<Order<T>> orders) 
{ 
    foreach (Order<T> order in orders) 
     Console.WriteLine(order.Delivery.ToString()); 
} 

選項2:也許你不知道什麼類型的訂單你實際上有。你真的想要一個「無論順序」。有人猜測將這個添加到C#中 - 推測功能被稱爲「mumble types」,如「(嘟嘟嘟嘟)」的順序。但是如果沒有這樣的語言功能,你需要有一些具體的類,你可以創建一個List。

因此,在您的示例中,您可以創建一個名爲IOrder的接口或稱爲Order或OrderBase的基類(可能是抽象的)。在任何一種情況下,您都無法將Delivery屬性放在該基類/接口上,因爲您不知道交付將會是什麼類型,所以您將不得不向IOrder添加另一種方法或屬性。例如,你可以在IOrder上放置一個DeliveryAsString屬性。

1

你不能只是說令,你必須說的什麼命令(即Order<???>) 這應該工作:

List<Order<ParcelDelivery>> orders = new List<Order<ParcelDelivery>>(); 

orders.Add(new CustomerOrder()); 
orders.Add(new CustomerOrder()); 
orders.Add(new CustomerOrder()); 
orders.Add(new CustomerOrder()); 
orders.Add(new CustomerOrder()); 

foreach (Order<ParcelDelivery> order in orders) 
{ 
    order.Delivery.ToString(); 
} 

然而,問題是,.NET不支持通用的多態,所以你可以」牛逼只是定義的變量爲Order<DeliveryStrategy>,並期望他們工作:(

1

Order<T>是一個編譯時抽象。 Order將是一個運行時間抽象,但在問題沒有Order

由於沒有Order,所以沒有List<Order>。有這些類型的集合:

List<Order<ParcelDelivery>> 
List<CustomerOrder> 
List<Order<ShippingContainer>> 
List<OverseasOrder> 
ArrayList 

假設你有這個集合:

ArrayList myOrders = GetOrders(); 

然後,你可以通過收集迭代,並獲得CustomerOrder情況是這樣的:

foreach(object someThing in myOrders) 
{ 
    CustomerOrder myOrder = someThing as CustomerOrder; 
    if (myOrder != null) 
    { 
    //work with myOrder 
    } 
} 

在同樣的方法,如果你有一個List<Order<ShippingContainer>>你可以從它得到OverseasOrder實例。

在.Net Framework 2.0中,這種技術是如何與運行時抽象一起工作的。 在.Net Framework 3.5中,將調用Enumerable.OfType<T>來替代執行過濾。