2009-06-03 94 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>来替代执行过滤。