4

特定のことが機能しているのに他の機能が機能していないという興味深い状況があり、その理由はわかりません。以下は私の状況を概算するコードです。オブジェクトの基本型によって実装されるジェネリック型をとるリポジトリに静的なものがあります。次に、そのジェネリック型に基づいた2つのレベルの派生クラスがあります。派生クラスの第1レベルは、基本型のジェネリックパラメーターを入力し、正常に機能しますが、ジェネリックパラメーターを入力したクラスから派生したクラスは、派生元の基本クラスの代わりには機能しません。

public class Vehicle<TVehicleType, TStorage>
{
}

public class Car : Vehicle<Car, ParkingLot>
{
}

public class PickupTruck : Car
{
}

public class Dealership <TDrivableVehicle>
{
    public static TDrivableVehicle GetVehicle<TVehicleType, TStorage>(TStorage lot)
         where TDrivableVehicle : Vehicle<TVehicleType, TStorage>, new()
    {
    }
}

public class CarDealership : Dealership<Car>
{
    public static Car GetDrivableVehicle(aCarParkingLot)
    {
        return Dealership.GetDrivableVehicle<Car, CarParkingLot>(aCarParkingLot); <-- Works fine
    }
}

public class PickupTruckDealership : CarDealership
{
    public static PickupTruck GetDrivableVehicle(aCarParkingLot)
    {
        return Dealership.GetDrivableVehicle<PickupTruck, CarParkingLot>(aCarParkingLot); <-- fails
    }
}

PickupTruckがその汎用ベースを理解するという点では、特定の側面は正しく機能しているように見えますが、拡張機能(ここには示されていません)および型を型パラメーターに渡すことは特に機能しません(GetDrivableVehicle呼び出し)。私の推測では、拡張メソッドはタイプを把握する必要があるため、タイプパラメーターの問題に関連していると思います。

これが機能しない理由や、それを回避するために何ができるかについてのアイデアはありますか?

4

3 に答える 3

2

コードを書き直して、失敗する可能性があると言ったところで、問題はトム・スミスが言っているとおりです。PickupTruck継承するCarため、Vehicle<Car, ParkingLot>ではなく、Vehicle<PickupTruck, ParkingLot>です。また、それは一般的な継承であるため、それ以外のものになることは不可能です。

私はあなたのコードがあなたが抱えている問題の要約された表現に過ぎないことを知っています-しかしそれが十分に近いなら、全体的なアーキテクチャについてここで私たちが行うことができるいくつかの有用な観察があるかもしれません。

私は、一般的なベースがそれらの派生した対応物を認識していることに反対していません-実際、それは工場にとって特に有用です。ただし、ほとんどの場合、それ以上の継承は即座に除外されます。

タイプレベルであまりにも多くの情報をエンコードしようとしています。Vehicle<TVehicleType, TStorage>ここに表示されている山かっこの数は別として、実際には、格納できるストレージのタイプを決定しているわずかに不調和な性質によって示唆されています。

私にとって、それは意味がありません。ParkingLot今日があるとしましょう。しかし、明日はHangar(カバーの下に保管されている車の場合)も取得します。これには、派生型もベースに渡されているという事実Vehicle<TDerived, ...>-エルゴParkingLotCarであり、2つのインスタンスが両方とも同じメーカー/モデルなどを表している場合でも、同等になるHangarCarことはありません。

それで、それを予期して、あなたはあなたが共通点を持っているところで継承に行きましたCar、しかしもちろんその時点でどんな継承も無意味CarですVehicle<Car,...>。多重継承でのみそうではない可能性がありますが、それでもParkingLot問題全体を回避することはできません。

なぜVehicle<,>派生タイプについて知る必要があるのか​​自問してみてください。それはあなたが単一のファクトリメソッドを持つことができるようにするためですか?Dealershipその場合は、、またはParkingLotタイプに入れる必要があります。車両ベースではありません:

public interface IVehicle {}
public interface ICar : IVehicle {} //because pickup trucks share some car traits
public interface IPickup : ICar, IVehicle {}
public interface IStorage {}

public class Car : ICar, IVehicle {}
public class Pickup : IPickup, ICar, IVehicle {}

public class ParkingLot : IStorage {}
public class Hangar : IStorage {}

public class Dealership
{
  public static TVehicle GetVehicle<TVehicle>(IStorage storage)
    where TVehicle : IVehicle, new()
  {

  }
}

//now you can specialise if you really need to

public class CarDealership
{
    public static Car GetVehicle(IStorage storage)
    {
        return Dealership.GetVehicle<Car>(storage);
    }
}

public class PickupDealership
{
    public static Pickup GetVehicle(IStorage storage)
    {
        return Dealership.GetVehicle<Pickup>(storage);
    }
}

これで、車両タイプ間の実行時の関係ができました。ICarさまざまな具象タイプが、またはIPickupインターフェース上の特性などの特性を共有できるようにします。しかし、あなたは車両とその保管場所との関係を壊したので、必要に応じて、から取得したり、桟橋からそれを運転したりすることがIVehicleできFootballPitchますRiverBed

于 2012-08-30T14:45:55.043 に答える
1

あなたが設定した方法では、 aPickupTruckは ではなく、Vehicle<PickupTruck, CarParkingLot>単にVehicle<Car, CarParkingLot>です。この種のテンプレートの無限再帰は、操作が非常に混乱する可能性があります。この特定の問題は、 を宣言するPickupTruck : Vehicle<PickupTruck, CarParkingLot>か、共分散をいじるか、クラス階層をリファクタリングして混乱を招くパターンを回避することで解決できます。

于 2012-08-30T14:12:57.043 に答える
0

基本クラスの代わりに派生クラスを使用しようとしています。これは機能しません。より派生したクラスの代わりに BASE クラスを使用できるはずです。その逆ではありません。Car をインターフェイス (ICar) に変換し、PickupTruck に ICar を実装させることができます。それはうまくいくでしょう。

反分散と共分散について読んでください。 http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx

于 2012-08-30T14:10:29.693 に答える