代码之家  ›  专栏  ›  技术社区  ›  Crispy

如何使用泛型在基类上使用foreach?

  •  2
  • Crispy  · 技术社区  · 16 年前

    Jon Skeet's 答复 this question .

    因此,我在上面的问题链接的问答中有以下代码。

     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();
    }
    

    编辑:添加了“海外订单”,以提供更好的示例。

    8 回复  |  直到 8 年前
        1
  •  6
  •   Lasse V. Karlsen    16 年前

    这里的问题是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();
        }
    }
    

        2
  •  2
  •   David Hay    16 年前

    通用性就是你在这里出错的地方。由于泛型的类型是在编译时编写的,因此您需要指出使用类型创建列表的顺序。

    如果您添加以下类型,它将编译:

    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();
            }
    

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

        3
  •  2
  •   Adam Sills    16 年前

    在您的情况下,没有Order类,只有Order<t交付>班

    abstract class Order {
        public abstract string DeliveryString();
    }
    
    abstract class Order<TDelivery> : Order {
        // methods omitted for brevity
    
        public override string DeliveryString() {
            return Delivery.ToString();
        }
    }
    
        4
  •  1
  •   Massimiliano    16 年前

    但是你没有 Order 班你有 Order<T> 班 这就是为什么你不能 List<Order>

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

    public abstract class OrderBase{ ... }
    ...
    public abstract class Order<TDelivery>:OrderBase where TDelivery : DeliveryStrategy { ... }
    
        5
  •  1
  •   Joe White    16 年前

    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());
    }
    

    mumble types (咕哝) “。但是如果没有这样的语言特性,您需要有一些具体的类,您可以列出这些类。

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

        6
  •  1
  •   Andriy Volkov    16 年前

    你不能只说顺序,你必须说什么的顺序。 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> 并期望它们发挥作用:(

        7
  •  1
  •   Amy B    16 年前

    Order<T> 是一个编译时抽象。 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实例。

    在.NETFramework2.0中,这种技术是如何处理运行时抽象的。 在.NETFramework3.5中,可以调用 Enumerable.OfType<T> 改为执行过滤。

        8
  •  0
  •   Peanut    16 年前

    要迭代顺序,您可以像这样使用它。。。

    orders.ForEach(委托(Order orderItem) { //所以需要一些处理 });

    如果你不想使用匿名方法,那么写一个方法,这样做。