tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルKeyedCollectionについて
記事No7546
投稿日: 2008/05/16(Fri) 16:50
投稿者kuroko
はじめまして。
いつも参考にさせていただいてます。

早速質問なのですが...
KeyedCollectionクラスを継承したクラスに型パラメータを定義して
その型をKeyedCollectionのキーの型に指定すると例外が発生します。

  Public Class MyCollection(Of TKey, TValue)
      Inherits KeyedCollection(Of TKey, TValue)

次のように値の型の指定のみなら例外は発生しません。

  Public Class MyCollection(Of TValue)
      Inherits KeyedCollection(Of String, TValue)

ちなみに、意味は無いですが型パラメータを定義して
使用しなかった場合も例外が発生します。

  Public Class MyCollection(Of T)
      Inherits KeyedCollection(Of String, Object)

ただし、例外が発生するといっても中断されるわけではなく、中断モードのときに
作成したクラスで宣言した変数にマウスカーソルを合わせると
"Count = 型 '{TypeLoadException}' の例外が発生しました"
と表示されるだけで動作自体には問題はありません。

このまま使っても問題ないのかわからず質問させていただきました。
よろしくお願いします。

開発環境: WindowsXP SP2, VS2005

[ツリー表示へ]
タイトルRe: KeyedCollectionについて
記事No7548
投稿日: 2008/05/16(Fri) 17:41
投稿者よねKEN
> KeyedCollectionクラスを継承したクラスに型パラメータを定義して
> その型をKeyedCollectionのキーの型に指定すると例外が発生します。
>
>   Public Class MyCollection(Of TKey, TValue)
>       Inherits KeyedCollection(Of TKey, TValue)

何の例外がどこで発生していますか?(後述されているTypeLoadExceptionですか?)
例外が発生している箇所を見れば、問題箇所は特定できると思いますが。

KeyedCollectionコレクションを継承する場合、最低限、GetKeyForItemメソッドを
オーバーライドする必要がありますが、どのように実装していますか?

試しに以下のように空実装をした場合、とりあえずコンパイルは通ります。

Public Class MyCollection(Of TKey, TValue)
      Inherits KeyedCollection(Of TKey, TValue)

    Protected Overrides Function GetKeyForItem (item As TValue) As TKey
        ' 要実装
    End Function
End Class

しかし、具体的に実装しようとした場合、
TValue型がどんな型かを予め知っていないとこのメソッドを実装して
TKey型を返すのは困難なように思います。(条件により不可能ではないと思いますが)

そういう意味で、KeyedCollectionを継承する場合、
TKeyやTValueについては閉じた型(型パラメータを含まない具体的な型)を
指定して継承するものではないかと思います。

[ツリー表示へ]
タイトルRe^2: KeyedCollectionについて
記事No7549
投稿日: 2008/05/16(Fri) 18:20
投稿者kuroko
よねKEN様、早速の回答ありがとうございます。

> 何の例外がどこで発生していますか?(後述されているTypeLoadExceptionですか?)
> 例外が発生している箇所を見れば、問題箇所は特定できると思いますが。

書いたつもりだったのですが説明がわかりづらくなってしまい申し訳ありません。
作成したクラスで宣言した変数を中断モードの状態でマウスカーソルを当てると
"Count = 型 '{TypeLoadException}' の例外が発生しました"
というツールチップが表示されます。
ビルド自体は問題なく通り、実行時にも例外によって中断されることはありません。

よねKEN様が提示していただいた空実装で次のコードを実行していただき
2行目以降で中断モードにして変数xの上にマウスカーソルを合わせると
例外を確認できると思います。

  Dim x As New MyCollection(Of String, Object)
  x.Add("item1")

型パラメータの定義がTValueのみの場合は例外は発生しません。

> しかし、具体的に実装しようとした場合、
> TValue型がどんな型かを予め知っていないとこのメソッドを実装して
> TKey型を返すのは困難なように思います。(条件により不可能ではないと思いますが)
>
> そういう意味で、KeyedCollectionを継承する場合、
> TKeyやTValueについては閉じた型(型パラメータを含まない具体的な型)を
> 指定して継承するものではないかと思います。

実際の実装ではTValueはキーにする値を持った抽象クラス(独自に定義)のみに制約し、
その値の型はTKeyにより決定されるようにしているためGetKeyForItemメソッドの
戻り値を返すことができます。
抽象クラスを継承したクラスを定義するだけで色々な型に対応できるので
汎用的に利用できるかなと思ってこのような実装にしてみました。

[ツリー表示へ]
タイトルRe^3: KeyedCollectionについて
記事No7573
投稿日: 2008/05/20(Tue) 09:51
投稿者よねKEN
土日ばたばたしていてすっかり返信するのを忘れていました。申し訳ないです。
(昨日は体調を崩して休んでおりました)

> 書いたつもりだったのですが説明がわかりづらくなってしまい申し訳ありません。
> 作成したクラスで宣言した変数を中断モードの状態でマウスカーソルを当てると
> "Count = 型 '{TypeLoadException}' の例外が発生しました"
> というツールチップが表示されます。
> ビルド自体は問題なく通り、実行時にも例外によって中断されることはありません。

明確な根拠を示せないのですが、調べたり実験したりした範囲では、
IDE周辺の不具合の可能性が高いと思っています。
(ちなみに試したのはVS2008でしたが、同じ現象を確認しました)

> よねKEN様が提示していただいた空実装で次のコードを実行していただき
> 2行目以降で中断モードにして変数xの上にマウスカーソルを合わせると
> 例外を確認できると思います。
>
>   Dim x As New MyCollection(Of String, Object)
>   x.Add("item1")
>
> 型パラメータの定義がTValueのみの場合は例外は発生しません。

イミディエイトウィンドウで、
? x
でも同様のことを確認できますね。
? x.Count
なら問題なく表示されます。
List<T>やDictionary<TKey, TValue>ではどうなるかを確認してもこの現象は発生しませんでした。

> > しかし、具体的に実装しようとした場合、
> > TValue型がどんな型かを予め知っていないとこのメソッドを実装して
> > TKey型を返すのは困難なように思います。(条件により不可能ではないと思いますが)
> >
> > そういう意味で、KeyedCollectionを継承する場合、
> > TKeyやTValueについては閉じた型(型パラメータを含まない具体的な型)を
> > 指定して継承するものではないかと思います。
>
> 実際の実装ではTValueはキーにする値を持った抽象クラス(独自に定義)のみに制約し、
> その値の型はTKeyにより決定されるようにしているためGetKeyForItemメソッドの
> 戻り値を返すことができます。

制約を付けているのであれば、私の危惧したところは問題ないですね。

> 抽象クラスを継承したクラスを定義するだけで色々な型に対応できるので
> 汎用的に利用できるかなと思ってこのような実装にしてみました。

実装としては特に問題ないと思うのですが、本題の現象の理由がわからないと
ちょっと気持ち悪いですね。
KeyedCollection<TKey, TItem>とその親のCollection<T>のソースコードを追ってみましたが、
今回の現象に繋がりそうな感じのする箇所は見つけられませんでした。

あまりお役に立てそうにありませんね(^^;

[ツリー表示へ]
タイトルRe^4: KeyedCollectionについて
記事No7583
投稿日: 2008/05/21(Wed) 15:42
投稿者kuroko
> 明確な根拠を示せないのですが、調べたり実験したりした範囲では、
> IDE周辺の不具合の可能性が高いと思っています。
> (ちなみに試したのはVS2008でしたが、同じ現象を確認しました)

私もいろいろと調べてみたのですが、わかったのは
もう一つ例外が発生していることぐらいです(T_T)

KeyedCollectionのItemsプロパティ(Protected ReadOnly)を
イミディエイトウィンドウで見ると次のような例外が発生していました。

{"間違った汎用引数の数と共に、アセンブリ 'mscorlib' でジェネリック
型 'System.Collections.ObjectModel.Collection`1' が
使用されています。":"System.Collections.ObjectModel.Collection`1"}

> 実装としては特に問題ないと思うのですが、本題の現象の理由がわからないと
> ちょっと気持ち悪いですね。

まったくです。
とりあえず今回は継承するときに型を指定して実装しようと思います。

お忙しい中、いろいろと調べていただきありがとうございました。

[ツリー表示へ]