VB のたまご

作成日: 2015/12/19, 更新日: 2015/12/19


アクセス修飾子を書かないで省略した場合、デフォルト値は何に設定されるのか?

アクセス修飾子って知ってる?

  •  アクセス修飾子って、知っていますか? Private とか、Public とかのやつです。 身内のデータなので、他の人からは見えないようにしたいとか、継承した人しか見えないようにしたいとか、操作できる範囲を設定できるやつですね。 アクセス修飾子は必ず付けましょうね、と教わってきたので宣言時は必ず付けています。その方が、パッと見てすぐ分かりますからね。

  •  ところで、たまに解説系のサンプルを見たときに、アクセス修飾子が書かれていないことがあります。 このサイトでも、アクセス修飾子を省略して書いている時があります。 私の場合は、命令数を少なく見せることで、読み取る情報が減るので、 分かってほしいメインとなる技術が、少しは理解しやすくなるのでは?という狙いがあり、そう書いている時があります。

  •  しかし、自分以外の、他の方が書くプログラムを見ると、あれ?この場合どうなるっけ?って思うことがあります。 自分で作ったプログラムについては、あまり思うことはありませんねー、なぜか。 ちなみに、各アクセス修飾子の特徴、スコープについては、だいたい分かります。 分からないのは、アクセス修飾子を省略して宣言した場合に設定される、デフォルト値です。

スポンサーリンク


デフォルト値は、何でしょう?

  •  クラス、構造体、インターフェース、モジュール、とそれぞれ見てみましょう。このサンプルでは、WindowsApplication プロジェクトのほかに、 ClassLibrary プロジェクトを作成しています。以下の各ソースは、ClassLibrary プロジェクト内に作成しておき、 WindowsApplication 内のクラスから、どう見えているのか調べました。


  • クラス
  • Class Class1                                ' Friend
    
        Property Name As String = String.Empty  ' Public
        Dim Age As Integer = 0                  ' Private
    
        Sub New()                               ' Public
            Me.Name = "taro"
            Me.Age = 25
        End Sub
    
        Sub New(name As String, age As Integer) ' Public
            Me.Name = name
            Me.Age = age
        End Sub
    
        Sub ShowMessage(msg As String)          ' Public
            Console.WriteLine(msg)
        End Sub
    
    End Class
    

  • 構造体
  • Structure Structure1                         ' Friend
    
        Property Name As String                  ' Public
        Dim Age As Integer                       ' Public
    
        Sub New(name As String, age As Integer)  ' Public
            Me.Name = name
            Me.Age = age
        End Sub
    
        Sub ShowMessage(msg As String)            ' Public
            Console.WriteLine(msg)
        End Sub
    
    End Structure
    

  • インターフェース
  • Interface Interface1                                      ' Friend
    
        Property Name As String                               ' Public
        Event Clicked(sender As Object, e As EventArgs)       ' Public
        Sub Button_Clicked(sender As Object, e As EventArgs)  ' Public
    
    End Interface
    

  • モジュール
  • Module Module1                               ' Friend
    
        Property Name As String = String.Empty   ' Public
        Dim Age As Integer = 0                   ' Private
    
        Sub ShowMessage(msg As String)           ' Public
            Console.WriteLine(msg)
        End Sub
    
    End Module
    
  •  結果はこのように、コンテナ系は Friend 、コンテナ内のメンバーは Public で、全て共通でした。 しかし、クラス内フィールド、モジュール内フィールドは、Private 、構造体フィールドは、Public というバラバラな結果となりました。 このことから、分かりやすい実装をするのであれば、メンバー定義には、Dim は使わないでアクセス修飾子を使って定義する、 Dim を使うのは、メソッド内かプロパティ内だけ、にした方が良さそうです。


スポンサーリンク


リフレクション経由で見てみよう!

  •  この調査は、メンバーにマウスオーバーしたときに表示されるツールチップを見たり、アクセスエラー内容を見て確認しました。 これって証明になりますよね?私の中の天使がささやきます。なるよ!しかし、私の中の悪魔がささやきます。そうかな?あいまいな気がするな。 ダメじゃねー?

  •  自分会議の結果、私のプログラマー魂に火が灯り、リフレクションで抽出した結果はどうなっているか? それが一致しているのであれば、正しいと証明できようぞ。という自分との戦いが始まったのでありました。


  • アクセス修飾子を選択するための列挙体
  • Enum AccessModifiers
        None
        [Private]
        [Protected]
        [Friend]
        [Protected_Friend]
        [Public]
    End Enum
    

  • 確認用ソース
  • Imports System.Reflection
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
            Try
    
                Dim dllFile As String = "ClassLibrary1.dll"
                Dim asm As Assembly = Assembly.LoadFrom(dllFile)
                Dim b As BindingFlags = BindingFlags.Public Or
                                        BindingFlags.NonPublic Or
                                        BindingFlags.Instance Or
                                        BindingFlags.Static Or
                                        BindingFlags.DeclaredOnly
    
                For Each t As Type In asm.GetTypes()
    
                    If Not t.FullName.Contains("ClassLibrary1.My") Then
                        Console.WriteLine(t.FullName)
    
                        For Each pi As PropertyInfo In t.GetProperties(b)
                            ' なぜか、PropertyInfo には、アクセス修飾子を調べるプロパティが無い。
                            ' StackOverflow で調べたところ、ゲッターメソッド、セッターメソッド(MethodInfo)の
                            ' それぞれのアクセス修飾子を見て、ゆるい方が、そのプロパティのアクセス修飾子と判断できるよ。とのこと。
    
                            Dim getterModifier As AccessModifiers = AccessModifiers.Private
                            Dim setterModifier As AccessModifiers = AccessModifiers.Private
    
                            If pi.CanRead Then
    
                                Dim mi As MethodInfo = pi.GetGetMethod(True)
                                Select Case True
                                    Case mi.IsPrivate : getterModifier = AccessModifiers.Private
                                    Case mi.IsFamily : getterModifier = AccessModifiers.Protected
                                    Case mi.IsAssembly : getterModifier = AccessModifiers.Friend
                                    Case mi.IsFamilyAndAssembly : getterModifier = AccessModifiers.Protected_Friend
                                    Case mi.IsPublic : getterModifier = AccessModifiers.Public
                                End Select
    
                            End If
    
                            If pi.CanWrite Then
    
                                Dim mi As MethodInfo = pi.GetSetMethod(True)
                                Select Case True
                                    Case mi.IsPrivate : setterModifier = AccessModifiers.Private
                                    Case mi.IsFamily : setterModifier = AccessModifiers.Protected
                                    Case mi.IsAssembly : setterModifier = AccessModifiers.Friend
                                    Case mi.IsFamilyOrAssembly : setterModifier = AccessModifiers.Protected_Friend
                                    Case mi.IsPublic : setterModifier = AccessModifiers.Public
                                End Select
    
                            End If
    
                            ' アクセス修飾子がゆるい方を取得
                            If getterModifier < setterModifier Then
                                getterModifier = setterModifier
                            End If
    
                            Select Case True
                                Case getterModifier = AccessModifiers.Private
                                    Console.WriteLine("type = Property, accessModifier = Private, name = {0}", pi.Name)
    
                                Case getterModifier = AccessModifiers.Protected
                                    Console.WriteLine("type = Property, accessModifier = Protected, name = {0}", pi.Name)
    
                                Case getterModifier = AccessModifiers.Friend
                                    Console.WriteLine("type = Property, accessModifier = Friend, name = {0}", pi.Name)
    
                                Case getterModifier = AccessModifiers.Protected_Friend
                                    Console.WriteLine("type = Property, accessModifier = Protected Friend, name = {0}", pi.Name)
    
                                Case getterModifier = AccessModifiers.Public
                                    Console.WriteLine("type = Property, accessModifier = Public, name = {0}", pi.Name)
    
                            End Select
    
                        Next
    
                        For Each fi As FieldInfo In t.GetFields(b)
    
                            Select Case True
                                Case fi.IsPrivate
                                    Console.WriteLine("type = Field, accessModifier = Private, name = {0}", fi.Name)
    
                                Case fi.IsFamily
                                    Console.WriteLine("type = Field, accessModifier = Protected, name = {0}", fi.Name)
    
                                Case fi.IsAssembly
                                    Console.WriteLine("type = Field, accessModifier = Friend, name = {0}", fi.Name)
    
                                Case fi.IsFamilyOrAssembly
                                    Console.WriteLine("type = Field, accessModifier = Protected Friend, name = {0}", fi.Name)
    
                                Case fi.IsPublic
                                    Console.WriteLine("type = Field, accessModifier = Public, name = {0}", fi.Name)
    
                            End Select
    
                        Next
    
                        For Each mi As MethodInfo In t.GetMethods(b)
    
                            Select Case True
                                Case mi.IsPrivate
                                    Console.WriteLine("type = Method, accessModifier = Private, name = {0}", mi.Name)
    
                                Case mi.IsFamily
                                    Console.WriteLine("type = Method, accessModifier = Protected, name = {0}", mi.Name)
    
                                Case mi.IsAssembly
                                    Console.WriteLine("type = Method, accessModifier = Friend, name = {0}", mi.Name)
    
                                Case mi.IsFamilyOrAssembly
                                    Console.WriteLine("type = Method, accessModifier = Protected Friend, name = {0}", mi.Name)
    
                                Case mi.IsPublic
                                    Console.WriteLine("type = Method, accessModifier = Public, name = {0}", mi.Name)
    
                            End Select
    
                        Next
    
                        Console.WriteLine("")
                    End If
    
                Next
    
            Catch ex As Exception
                Console.WriteLine(ex.ToString())
            End Try
    
        End Sub
    
    End Class
    

  • 出力結果
  • ClassLibrary1.Class1
    type = Property, accessModifier = Public, name = Name
    type = Field, accessModifier = Private, name = _Name
    type = Field, accessModifier = Private, name = Age
    type = Method, accessModifier = Public, name = get_Name
    type = Method, accessModifier = Public, name = set_Name
    type = Method, accessModifier = Public, name = ShowMessage
    
    ClassLibrary1.Interface1
    type = Property, accessModifier = Public, name = Name
    type = Method, accessModifier = Public, name = get_Name
    type = Method, accessModifier = Public, name = set_Name
    type = Method, accessModifier = Public, name = add_Clicked
    type = Method, accessModifier = Public, name = remove_Clicked
    type = Method, accessModifier = Public, name = Button_Clicked
    
    ClassLibrary1.Interface1+ClickedEventHandler
    type = Method, accessModifier = Public, name = BeginInvoke
    type = Method, accessModifier = Public, name = EndInvoke
    type = Method, accessModifier = Public, name = Invoke
    
    ClassLibrary1.Module1
    type = Property, accessModifier = Public, name = Name
    type = Field, accessModifier = Private, name = _Name
    type = Field, accessModifier = Private, name = Age
    type = Method, accessModifier = Public, name = get_Name
    type = Method, accessModifier = Public, name = set_Name
    type = Method, accessModifier = Public, name = ShowMessage
    
    ClassLibrary1.Structure1
    type = Property, accessModifier = Public, name = Name
    type = Field, accessModifier = Private, name = _Name
    type = Field, accessModifier = Public, name = Age
    type = Method, accessModifier = Public, name = get_Name
    type = Method, accessModifier = Public, name = set_Name
    type = Method, accessModifier = Public, name = ShowMessage
    
  •  ネストしまくりソースです。自動生成系のいろいろなものも混ざっていますね。 しかも、今気づきましたが、コンテナ系のアクセス修飾子のことすっかり忘れていました;;。 プロパティのアクセス修飾子の取得方法にハマってしまい、こればかりに気を取られていました。 しかも、私の中のプログラマー魂の火は燃え尽きて、無事鎮火しましたので、取得できていませんが、これにてお開きとさせていただきます。 それでは、良い一日を!

  •  最後までこの記事を読んでいただき、ありがとうございました。


スポンサーリンク