前回、[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」のように逆向きも作りたいところなのですが、単純な代入演算子(=演算子)はオーバーライドできないので、無理なのです。仕方がないので二項演算子と組わせた「*=」とか「+=」とかならば可能なので、その話は後日。「+=」はデリゲート関係で使っていますね。