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が基本的に 2 つの異なる型であることです。

あなたはこれを行うことができます:

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

ジェネリックは、ここで間違っているところです。ジェネリックの型はコンパイル時に作成されるため、型を使用してリストを作成する順序の種類を示す必要があります。

次のように型を追加するとコンパイルされます。

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を知らないことを除いて。

2 つの可能性:

オプション 1:foreachジェネリック メソッドの内部をラップします。

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

オプション 2: 実際にどのような種類の注文があるかわからない場合があります。あなたは本当に「何でも注文」したいのです。これを C# に追加することについて憶測がありました -- 推測された機能は、 「 (mumble mumble)の順序」のように「 mumble types 」と呼ばれます。しかし、そのような言語機能がない場合は、リストを作成できる具体的なクラスが必要です。

したがって、あなたの例では、IOrder というインターフェイス、または Order または OrderBase という基本クラス (おそらく抽象クラス) を作成できます。いずれの場合も、Delivery のタイプがわからないため、その基本クラス/インターフェイスに Delivery プロパティを配置することはできません。そのため、IOrder に別のメソッドまたはプロパティを追加する必要があります。たとえば、DeliveryAsString プロパティを IOrder に配置できます。

于 2009-06-03T14:42:37.490 に答える
1

Order とだけ言うことはできません。Order of what (つまり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) { //一部の処理 });

匿名メソッドを使用したくない場合は、メソッドを作成してください。

于 2009-06-03T14:40:12.660 に答える