2009-05-07 7 views
4
interface IFolderOrItem<TFolderOrItem> where TFolderOrItem : FolderOrItem {} 

abstract class FolderOrItem {} 

class Folder : FolderOrItem {} 

abstract class Item : FolderOrItem {} 

class Document : Item {} 

は今、私はこのようなSTHをやろうとしている:なぜこのキャストはできないのですか?

class Something 
{ 
    IFolderItemOrItem<Item> SelectedItem { get; set; } 
    void SomeMagicMethod() 
    { 
     this.SelectedItem = (IFolderOrItem<Item>)GetMagicDocument(); 
     // bad bad bad ... ?? 
    } 
    IFolderOrItem<Document> GetMagicDocument() 
    { 
     return someMagicDocument; // which is of type IFolderOrItem<Document> 
    } 
} 

は、この作業を取得するための任意の可能性はありますか?

+0

どのようなエラーメッセージが表示されますか?コンパイル時間? –

+0

キャストなし=コンパイル時間。キャスト=実行時間 –

+0

(私の返信にあなたのコメントごとに注意してください、少なくともそれが動作する非ジェネリックベースインターフェイスのいくつかのノートを追加しました) –

答えて

13

私はそれを正しく読んであれば、問題はその理由だけでFoo : Barです...、は、いくつかのケースでは、C#4.0での分散が選択肢かもしれISomething<Foo> : ISomething<Bar> ...

ということを意味するものではありませありません。あるいは、ジェネリックメソッドで行うことができることがあります(ただし、ここで役立つかどうかは不明です)。


あなたはおそらく非ジェネリックベースのインタフェースである(以下と)C#3.0で行うことができます最も近い:

interface IFolderOrItem {} 
interface IFolderOrItem<TFolderOrItem> : IFolderOrItem 
    where TFolderOrItem : FolderOrItem { } 

一般的に、ベース・インターフェースは持っているだろう、例えば、Type ItemType {get;}へ考慮中の実数型を示します。次いで、使用:

構築タイプが同じ変換に従う

25.5.6コンバージョン:

IFolderOrItem SelectedItem { get; set; } 
... 
public void SomeMagicMethod() 
{ 
    this.SelectedItem = GetMagicDocument(); // no cast needed 
    // not **so** bad 
} 

スペックから、これは§25.5.6(ECMA 334 V4)に関し規則(§13) は非ジェネリック型と同様です。 これらの規則を適用する場合、構築された型の基本クラスと のインタフェースは、§25.5.3で説明されているように、 とする。

以外の構成の参照型の間には、特別な変換はありません。特に、 の配列型とは異なり、 参照型は 共変型変換(19.5)を許可しません。この タイプList<B>BAに由来 場合でもList<A>を(暗黙的または明示的のいずれか )は 変換を持っていないことを意味します。同様に、List<B>から List<object>には の変換が存在しません。

[注: の根拠は、これは簡単である: List<A>への変換が許可された場合、その後明らかに、 一つはリストに入力Aの値を格納することができます。しかし、これはタイプList<B>の リスト内のすべてのオブジェクトは、常にタイプB、または他の予期しない障害の値 であることを不変 を破る コレクションクラスに割り当てるときに発生する可能性があります。終了ノート]

同じことがインターフェイスに適用されます。これにより、C#4.0ではのビットが変更される場合があります。

+0

あなたは私にこのヒントを与えるためにいくつかのヒントを与えることができますか? –

+1

トリッキー...それは* IFolderOrItem ではありません - それをラップしないと動作しません。インタフェースのメンバーに応じて、4.0で追加の修飾子を使用して*動作する可能性があります。それ以外の場合は...おそらく非ジェネリックインターフェイスを宣言してください... –

+0

+1:あなたが何かを見つけるだろうと知っていました:) –

6

コンパイラが実装されている限り、IFolderOrItem<Document> & IFolderOrItem<Item>は全く異なる2つのタイプです。

DocumentItemを継承することができるが、私はC#の仕様の関連部分へのリンクを投稿するマークやジョンに頼ってるIFolderOrItem<Item>

IFolderOrItem<Document>継承しません。

+0

lol - しかし私これはC#3.0の仕様にないものの1つで、これは考慮されていないためだと考えています。しかし、4.0仕様には何かがあるはずです。 –

+0

うそを言いなさい...更新;-p –

3

キャストは汎用引数ではなく、クラス全体で機能するという問題があります。ドキュメントはTrueをItemから継承しますが、IFolderOrItem < Document>はIFolderOrItemから継承しません< Item>、またそれには関係ありません。

2

それはこのように動作する理由を理解するために例:

はIFolderOrItemは方法、例えば、空の追加(T要素)を公開したとします。

IFolderOrItemの実装では、パラメータがドキュメントであると想定されます。

IFolderItemOrItemとしてIFolderOrItemをキャストした場合、誰かがTをItemとするCreate(T)メソッドを呼び出すことができます。

アイテムがドキュメントではないため、アイテムからドキュメントへのキャストは無効です。

これを行う唯一の方法は、インターフェイスの非ジェネリックバージョンを作成し、オブジェクトをパラメータとして許可し、実装内のオブジェクトのタイプをチェックすることです。

関連する問題