2

这个问题是尝试Jon Skeet对这个问题的回答的结果。

所以我有以下代码基于上述问题链接的问答。

 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 以提供更好的示例。

4

8 回答 8

6

这里的问题是 Order 是一个泛型类,因此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();
    }
}

或者...您可以将 Order 重新定义为非泛型,在这种情况下,您将失去一些强类型。

于 2009-06-03T14:38:23.740 回答
2

泛型是你在这里出错的地方。由于泛型的类型是在编译时编制的,因此您需要指出您使用类型创建列表的 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();
        }

也许这不再是您想要的,但是如果您需要能够在没有预定类型的情况下进行设置,则必须以不同的方式进行。

于 2009-06-03T14:39:17.577 回答
2

在您的情况下,没有 Order 类,只有 Order<TDelivery> 类。

如果您想在不了解任何特定子类型(或通用参数)的情况下通用地处理订单,则需要将所需内容抽象到基类或接口中,并使用新订单类上的方法对 Delivery.ToString 进行外观。

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

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

    public override string DeliveryString() {
        return Delivery.ToString();
    }
}
于 2009-06-03T14:40:30.943 回答
1

但是你没有任何Order课程……你有Order<T>课程。这就是你不能List<Order>上课的原因。

如果您想为现在可以在列表中使用的所有订单创建一个基类,您应该尝试这种方式:

public abstract class OrderBase{ ... }
...
public abstract class Order<TDelivery>:OrderBase where TDelivery : DeliveryStrategy { ... }
于 2009-06-03T14:39:51.520 回答
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 ”,如“Order of (mumble mumble) ”。但是在没有这样的语言特性的情况下,你需要有一些具体的类,你可以制作一个列表。

因此,在您的示例中,您可以创建一个名为 IOrder 的接口,或一个名为 Order 或 OrderBase 的基类(可能是抽象类)。在任何一种情况下,您都不能在该基类/接口上放置 Delivery 属性,因为您不知道 Delivery 将是什么类型,因此您必须向 IOrder 添加另一个方法或属性。例如,您可以在 IOrder 上放置 DeliveryAsString 属性。

于 2009-06-03T14:42:37.490 回答
1

你不能只说 Order,你必须说 Order of what (ie 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>并期望它们工作:(

于 2009-06-03T14:43:23.263 回答
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>来执行过滤。

于 2009-06-03T16:06:24.120 回答
0

要迭代 Order,您可以像这样使用它...

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

如果您不想使用匿名方法,请编写一个方法,请执行此操作。

于 2009-06-03T14:40:12.660 回答