前回、[C#] VB6.0風にC#でデフォルトプロパティを作る | Moonmile Solutions Blog の続きです。と言うか、こっちを先に書かないと訳が分からないですよね。
Public Class Form1
''' <summary>
''' インデックスを利用した例
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim obj As New DefaultClass
' 配列も関数呼び出しも「()」なので、関数呼び出しに見えるのが難点か
Debug.Print(obj(10))
Debug.Print(obj("key"))
Debug.Print(obj.Item(10))
Debug.Print(obj.Item("key"))
End Sub
''' <summary>
''' 暗黙の型変換を使う
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
Dim obj As New DefaultClass
Dim name As String = obj
Debug.Print("name:{0}", name)
Dim num As Integer = obj
Debug.Print("num:{0}", num)
End Sub
End Class
Public Class DefaultClass
Public Sub New()
Me.ItemName = "DefaultClass"
Me.ItemNum = 10
End Sub
''' <summary>
''' デフォルトプロパティを作る
''' </summary>
''' <param name="i"></param>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Default Public ReadOnly Property Item(i As Integer) As String
Get
Return String.Format("item-int {0}", i)
End Get
End Property
Default Public ReadOnly Property Item(name As String) As String
Get
Return String.Format("item-name {0}", name)
End Get
End Property
Public Property ItemName As String
Public Property ItemNum As Integer
''' <summary>
''' 暗黙のキャスト
''' </summary>
''' <param name="obj"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Shared Narrowing Operator CType(obj As DefaultClass) As String
Return obj.ItemName
End Operator
Public Shared Narrowing Operator CType(obj As DefaultClass) As Integer
Return obj.ItemNum
End Operator
End Class
もともと、既定のプロパティという考え方が、VB6.0から来ているので(正確にはVB3.0の頃ですかね?)VB.NET のほうが素直に書けます。
「obj(10)」のようにインデックスを使う場合には、「Default」というキーワードを使います。上記のソースの場合には、Item プロパティを多重定義しているので、Integer 型、String 型の両方の Item プロパティの定義に Default を設定します。
暗黙の変換のほうは「Narrowing」というキーワードですね。これが C# の implicit にあたります。逆に、明示的な変換のほうは「Widening」というキーワード。C# で云えば explicit です。
暗黙の変換を使うと、
Dim name As String = obj
Debug.Print("name:{0}", name)
Dim num As Integer = obj
Debug.Print("num:{0}", num)
という書き方ができて、対象のオブジェクトから値を取り出すときに便利です(つーかかえってややこしいかも)。取り出す利用者側として、「name」「num」の型はわかっているので「name = obj」、「num = obj」とやっても、それぞれの string 型、integer 型を類推させることが可能、ということです。普通は「name = obj.name」のように目的のプロパティを指定する訳ですが、取り出す string 型が一種類しかないのであれば「name = obj」としても良かろうという意味ですね。
本当は、「obj = name」のように逆向きも作りたいところなのですが、単純な代入演算子(=演算子)はオーバーライドできないので、無理なのです。仕方がないので二項演算子と組わせた「*=」とか「+=」とかならば可能なので、その話は後日。「+=」はデリゲート関係で使っていますね。
