2012-05-08 11 views
2

実装クラスのインターフェイスプロパティにアクセスしようとすると問題が発生しています。問題は、実行時に特定の(Cat)型しか持たないため、キャストしようとするとアプリケーションが壊れてしまうことです。ジェネリックスを使用したキャスト

は、ここで私が持っているものだ:型が一致しない場合

public class Animal {} 
public class Cat : Animal {} 

public interface IPetSitter {} 
public interface IPetSitter<T> IPetSitter where T : Animal { 
    T Pet { get; set; } 
} 

public class Kid { } 

public class NeighborhoodKid : Kid, IPetSitter<Animal> { 
    Animal Pet { get; set; } 
} 

// --- Implementation --- 

// Kid Timmy is instantiated elsewhere 
// Animal type "A" is passed in dynamically 

if (Timmy is IPetSitter) { 
    ((IPetSitter<A>)Timmy).Pet = new A(); 
} 

このキャストはエラーになります。

public interface IPetSitter { 
    object Pet { get; set; } 
} 

public interface IPetSitter<T> : IPetSitter where T : Animal { 
    new T Pet { get; set; } 
} 

// --- Implementation --- 

NeighborhoodKid Timmy = new NeighborhoodKid(); 
((IPetSitter)Timmy).Pet = new Cat(); 

しかし、これは、[object pet]と[Cat Pet]の両方のプロパティを持つようにIPetSorterを実装するものに強制します。

私は何か考えていただければ幸いです。ありがとう。

UPDATE:私が最初にそれをより明確にしているはずですが、時々私はKidクラス、時にはNeighborhoodKidクラスを作成します。だから私はIPetSitter<T>にキャストする必要があります。私が作った子供はすべて座っているペットになるわけではありません。これは不気味な音を開始しています。

+3

「Timmy.Pet = new Cat();」だけではないのはなぜですか? – SwDevMan81

+0

'NeighborhoodKid'は必ずしも' Pet'プロパティを持っていないので動作しません。それを得るには、ある種の 'IPetSitter 'としてそれをキャストする必要があります。 – Montlebalm

答えて

0

最終的に、TimmyはNeighborhoodKidとして初期化されました。つまり、ペットは、彼のために、動物として。ティミーはIPetSitter<Animal>で、IPetSitter<Cat>にキャストできません。

でも、Cat:Animalと仮定すると、逆のことができます。

この:あなたは本当にそのキャストで何もしていないので、IPetSitter<Animal> - ちょうどペットのプロパティにアクセス:ティミーは本当にNeighborhoodKid以来、IPetSitter<Animal>あるので

((IPetSitter<Animal>)Timmy).Pet = new Cat(); 

は実際に単に動作します。

それ以降の行の問題は、ペットにアクセスしたり、Catを入れたりしていないことです。これは問題のあるティミーをIPetSitter<Cat>にキャストしています。あなたはそれがそうでないものに落としています。

いつでもアップキャストできますが、オブジェクトを初期化したものにのみダウンキャストできます。あなたはNeighborhoodKidは、動物自体を含めて、動物の任意の並べ替えのIPetSitterになりたい場合は

、あなたが実行する必要があります。

public class NeighborhoodKid<T> : IPetSitter<T> where T : Animal 
{ 
    ... 
} 

そのように、それが一般的であり、かつどちらかである何かであることに、それを制約します直接的にも間接的にも、動物や動物から派生したもの。

あなたはnew NeighborhoodKid<Animal>()としてそれを初期化した場合(別名にキャスト)としてそれでも、あなたはそれを見てすることはできませんIPetSitter<Cat>、NeighborhoodKidコンストラクタに与えられた一般的なTパラメータだったので、それがIPetSitter<Animal>(のように初期化されたため、 Animal、およびIPetSitterジェネリックパラメータに渡されます)。

+0

私はクラスをハードコーディングしていたら修正する方法を知っていますが、実行時には 'Cat'しか持っていません。本当に、私はちょうど 'ペット 'プロパティにアクセスしたいですが、私はキャスティングの問題にぶつかっています。 – Montlebalm

+0

しかし、「ティミー」には「ペット」がありません! 'Animal'プロパティを持っています! – SimpleVar

+0

すべてこれは、他の場所で指定されたタイプに基づいて動的に発生しています。私は 'PetSitter 'ではない 'NeighborhoodKid'をインスタンス化することがあります。私は該当する場合は 'Pet'プロパティを設定したいが、そうでないときは無視する。私はそれをより明確にすべきだった。最初の質問をより詳細に更新しました。 – Montlebalm

0

問題は、あなたが

public class NeighborhoodKid : IPetSitter<Animal> 
{ 
    Animal IPetSitter<Animal>.Pet { get; set; } 
} 

なく

public class NeighborhoodKid : IPetSitter<Cat> 
{ 
    Cat IPetSitter<Animal>.Pet { get; set; } 
} 

または

public class NeighborhoodKid<T> : IPetSitter<T> where T : Animal 
{ 
    Cat IPetSitter<T>.Pet { get; set; } 
} 
0

なぜだけではなくTimmy.Pet = new Cat();を定義したということでしょうか? ちょうどそれpublic作成し、youllはすべてのセットで:

public class NeighborhoodKid : Kid, IPetSitter<Animal> 
{ 
    public Animal Pet { get; set; } 
} 

あなたはIPetSitterから継承doesntのNeighborhoodKidを作成する場合は、セッターは文句を言わない空くこと。

public class LazyNeighborhoodKid : Kid 
{ 
    // Nothing here, hes not a Pet Sitter, can access Pet 
} 
0

私は実際にコレクションの有用性を除いてジェネリックのファンではありません。そのためです。すべてのNeighborhoodKidを特定の種類のAnimalにバインドする必要があります。ティミーが猫や犬を見ることができたら?それぞれのティミー・インスタンスを作成しますか?

代わりに、私はあなたがインスタンスレベルで動物型を強制すると考えています。例えば、(私は簡潔にするための型の一部を切り捨ててきました):

public interface IAnimal {...} 

public class Cat : IAnimal {...} 

public interface IPetSitter 
{ 
    IAnimal Pet { get; set; } 
} 

public class Kid : IPetSitter 
{ 
    public Kid (params Type[] allowedPets) { 
     _allowedPets = allowedPets; 
    } 

    readonly IEnumerable<Type> _allowedPets; 

    IAnimal _pet; 
    public IAnimal Pet 
    { 
     get { 
      return _pet; 
     } 
     set { 
      if (!_allowedPets.Contains(value.GetType()) { 
       throw new InvalidArgumentException("This instance does not support " + value.GetType().Name + "."); 
      } 
      _pet = value; 
     } 
    } 
} 

あなたは、インスタンス・レベルであなたの執行を離れる場合、あなたは必ずしもちょうど設定し、具体的なキャストを使用する必要はありませんプロパティ。

関連する問題