此问题是尝试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();
}
编辑:添加了OverseasOrder以提供更好的示例。
答案 0 :(得分: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();
}
}
或者......你可以将Order重新定义为非泛型,在这种情况下你会失去一些强有力的输入。
答案 1 :(得分: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();
}
也许这不再是你想要的了,但是如果你需要能够在没有预定类型的情况下进行设置,那么你必须采用不同的方式。
答案 2 :(得分:2)
在您的情况下,没有订单类,只有订单&lt; TDelivery&gt;类。
如果您想在不知道任何特定子类型(或通用参数)的情况下处理订单,则需要将您需要的内容抽象到基类或接口中,并使用新方法对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();
}
}
答案 3 :(得分:1)
但你没有任何Order
课程......你有Order<T>
课程。
这就是为什么你不能List<Order>
上课。
如果您想为列表中现在可以使用的所有订单创建基类,您应该尝试这种方式:
public abstract class OrderBase{ ... }
...
public abstract class Order<TDelivery>:OrderBase where TDelivery : DeliveryStrategy { ... }
答案 4 :(得分: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”,如“(mumble mumble)的顺序”。但是如果没有这样的语言特性,你需要有一些具体的类,你可以创建一个列表。
因此,在您的示例中,您可以创建一个名为IOrder的接口,或一个名为Order或OrderBase的基类(可能是抽象的)。在任何一种情况下,您都不能在该基类/接口上放置Delivery属性,因为您不知道Delivery将是什么类型,因此您必须向IOrder添加另一个方法或属性。例如,您可以在IOrder上放置一个DeliveryAsString属性。
答案 5 :(得分: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>
并期望它们起作用:(
答案 6 :(得分: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>
来执行过滤。
答案 7 :(得分:0)
要迭代订单,您可以像这样使用它......
orders.ForEach(delegate(Order orderItem) { //所以一些处理 });
如果您不想使用匿名方法,请编写一个方法,这样做。