型の比較について教えて下さい。

タグの編集
投稿者 たこ  (その他) 投稿日時 2021/6/21 05:51:12
稚拙な質問なのですが、以前にも一度ここで教えて頂いたことがありましたので、質問失礼します。

Visual Studio2017/.NET Framework4.6.1/VBのWindowsFormアプリケーションです。

型の比較について教えて下さい。
ある変数「obj」が特定の型であるかどうかを判別する際、TypeOf や GetType を使うと思います。
配列や Generic のとき、どうすればいいのか分からず、調べたのですが、
継承されている場合の比較のやり方が分かりません。

例えば、
List(Of T) を継承した SubListA(Of T) の、
T の比較はできたのですが、SubListA(Of) であることの比較が、分かりません。
説明が下手かと思いますので、コードの7番目の所です。
9番目と10番目の部分もどう書けば良いのかさっぱりです。

またこちらはついでですが、GetType (Type型)による比較をする際(コードの3番目の所)
・Equalsメソッド
・Is 演算子
・= 演算子
Type型の比較おいて、この3種類はどれも同じものと思って良いのでしょうか。
またもしくは、一般的には、どういう理由でどれを使いますか?

教えてくださる方居ましたら、ご教示ください。

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim ss As New System.Text.StringBuilder
        Dim obj As Object, t As Type

        obj = New SubClassA
        t = obj.GetType
        If TypeOf obj Is ClassA Then
            ss.AppendLine("1,基底クラスを含む、型の一致")
        End If
        If GetType(ClassA).IsAssignableFrom(t) Then
            ss.AppendLine("2,基底クラスを含む、型の一致")
        End If
        If GetType(SubClassA) = t Then
            ss.AppendLine("3,基底クラスを含まない、型の一致")
        End If

        obj = New SubClassA() {}
        t = obj.GetType
        If t.IsArray AndAlso GetType(ClassA).IsAssignableFrom(t.GetElementType) Then
            ss.AppendLine("4,objは、配列 ClassA() と一致")
        End If

        obj = New List(Of SubClassA)
        t = obj.GetType
        If t.IsGenericType AndAlso
            GetType(List(Of)).IsAssignableFrom(t.GetGenericTypeDefinition) Then
            ss.AppendLine("5,objは、List(Of) と一致")
        End If
        If t.IsGenericType AndAlso
            t.GenericTypeArguments.Count = 1 AndAlso
            GetType(ClassA).IsAssignableFrom(t.GenericTypeArguments(0)) Then
            ss.AppendLine("6,objは、ジェネリック(Of ClassA) と一致")
        End If

        obj = New SubListA(Of SubClassA)
        t = obj.GetType
        If t.IsGenericType AndAlso
            GetType(List(Of)).IsAssignableFrom(t.GetGenericTypeDefinition) Then '一致してくれない 
            ss.AppendLine("7,objは、List(Of) と一致")
        End If
        If t.IsGenericType AndAlso
            t.GenericTypeArguments.Count = 1 AndAlso
            GetType(ClassA).IsAssignableFrom(t.GenericTypeArguments(0)) Then
            ss.AppendLine("8,objは、ジェネリック(Of ClassA) と一致")
        End If

        obj = New SubListB
        t = obj.GetType
        If t.IsGenericType AndAlso
            GetType(List(Of)).IsAssignableFrom(t.GetGenericTypeDefinition) Then '書き方がさっぱり分かりません 
            ss.AppendLine("9,objは、List(Of) と一致")
        End If
        If t.IsGenericType AndAlso
            t.GenericTypeArguments.Count = 1 AndAlso
            GetType(ClassA).IsAssignableFrom(t.GenericTypeArguments(0)) Then '書き方がさっぱり分かりません 
            ss.AppendLine("10,objは、ジェネリック(Of ClassA) と一致")
        End If

        MsgBox(ss.ToString)
    End Sub

    Private Class ClassA
    End Class
    Private Class SubClassA : Inherits ClassA
    End Class
    Private Class SubListA(Of T) : Inherits List(Of T)
    End Class
    Private Class SubListB : Inherits List(Of SubClassA)
    End Class
投稿者 るきお  (社会人) 投稿日時 2021/6/21 21:10:03
何か説明されていないこだわりを秘めているように感じますが、

ひとまず、7 は obj が List(Of T)自身かそれを継承したものであるかを判定すればよいのですよね?

次のプログラムでどうでしょうか?
Dim obj As Object = New SubListA(Of SubClassA)

Dim baseType = obj.GetType

While baseType.FullName <> "System.Object"
    Dim name As String = baseType.FullName

    If name.StartsWith("System.Collections.Generic.List`"Then
        MsgBox("7,objは、List(Of) と一致")
    End If

    baseType = baseType.BaseType
End While


8 は obj が List(Of T)自身かそれを継承したものであり、かつ、T が ClassA自身かそれを継承したものであるという判定すればよいのですよね?

Dim obj As Object = New SubListA(Of SubClassA)

Dim baseType = obj.GetType

While baseType.FullName <> "System.Object"
    Dim name As String = baseType.FullName

    If name.StartsWith("System.Collections.Generic.List`"Then
        Dim argType = baseType.GetGenericArguments(0)

        While argType.FullName <> "System.Object"
            Dim argTypeName = argType.FullName
            If argTypeName = "WindowsApp1.Form1+ClassA" Then
                MsgBox("8,objは、ジェネリック(Of ClassA) と一致")
            End If
            argType = argType.BaseType
        End While
        Exit While
    End If

    baseType = baseType.BaseType
End While


多分、私が紹介したプログラムでできることはわかっているけど、何かこだわっている制約があって、その制約を前提にどう実現するかということを気にされているのかなと感じました。

最近はこの手のプログラムはあまりはやっておらず、インターフェースや拡張メソッドを活用する方向性のように思います。
特にこのようなクラスの静的な定義を解析するプログラムは拡張メソッドに対応できませんから、本当に練習とか力試しの用途になるのではないかと思います。

何かの静的コード解析やメトリックで役に立つかどうか…。よろしければ、たこさんがこのようなプログラムに関心を持っている理由を教えてください。
投稿者 たこ  (その他) 投稿日時 2021/6/22 01:21:56
るきお様、解答ありがとうございます。
すみません、仕事でも何でも無くただの趣味で、制約も何も有りません・・・。
偏った知識で奇妙なコードで申し訳ないです・・・。

なるほどBaseTypeを再起すれば良かったのですね。
7,9,10、分からなかった部分、綺麗に判定できました。
感謝です。


前述のように制約なんてものは有りませんが、
経緯は、PropertyGrid で動的なデフォルト値を作りたくて・・・です。
インターフェースや拡張メソッドも使っていますが、
確かに今考えると、Object型を使う必要はなかったかもしれません。
ですが、私の場合本当に趣味で書いてるだけなので、
分からなかったことが書けるようになって満足です。

また機会ありましたら、掲示板利用させてもらえると幸いです。