簡體   English   中英

VB.NET中的默認屬性?

[英]Default properties in VB.NET?

there was an attribute you could decorate a class with to specify a default property. 在.NET的早期階段,我有一個屬性可以裝飾一個類來指定一個默認屬性。

根據我發現的一些文章,這似乎在某個時候已經從框架中被淘汰,因為它有點令人困惑,我可以看到這是怎么回事。

還有,還有另一種方法來獲得它提供的功能嗎?

它看起來像這樣:

<DefaultProperty("Value")> _  
Public Class GenericStat
    ...
    Public Property Value() As Integer
        ...
    End Property
    ...
End Class

這允許你做Response.Write(MyObject)而不是Response.Write(MyObject.Value) ...這不是一個非常笨重的例子,但在一些復雜的面向對象的上下文中它有點可怕。 如果有更好的方法,請告訴我。

注意:我不是在尋找Default關鍵字,它只能用於帶參數的屬性。

那么,.NET框架確實有一個默認成員的概念。 主要成分是DefaultMemberAttribute類和Type.GetDefaultMembers()。 在VB.NET中,指定默認成員是語言語法的一部分:

  Public Class Sample
    Private mValue As Integer
    Default Public ReadOnly Property Test(ByVal index As Integer) As Integer
      Get
        Return index
      End Get
    End Property
  End Class

像這樣使用它:

  Sub Main()
    Dim s As New Sample
    Console.WriteLine(s(42))
    Console.ReadLine()
  End Sub

編譯器通過自動發出[DefaultMember]來實現此目的。 但是這有一個限制,該屬性必須有一個索引參數,專門用於避免語法歧義。 明確指定屬性時,不會強制執行此限制:

  <System.Reflection.DefaultMember("AnotherTest")> _
  Public Class Sample
    Public ReadOnly Property AnotherTest() As Integer
      Get
        Return 42
      End Get
    End Property
  End Class

但是,默認成員只能通過允許這種語法的語言作為默認值訪問。 我不知道.NET中的一個例子,它在COM時代被用過,比如VB6。 這也是VB6擁有Set關鍵字背后的核心原因,它解決了歧義,並指出“我的意思是對象,而不是對象的默認屬性”。 當時很多初學Visual Basic程序員都非常痛苦的語法細節。

C#具有完全相同的規則,但不允許相同的靈活性。 您之前可能已經看過索引器:

  public class Sample {
    public int this[int index] {
      get { return index; }
    }
  }

此代碼還使編譯器輸出[DefaultMember]屬性。 該屬性中的命名屬性是“Item”。 這就是為什么你看到索引器在MSDN Library中記錄並索引為“Item”的原因。

我發現你可以使用Widening Operator CType完全按照原始海報的要求進行上面提到但沒有太多細節,所以我完全錯過了它,因為我試圖找到這個問題的答案。 此方法本身並未定義默認屬性,但它實現了相同的結果。

Public Class GenericStat
    ...
    Public Property Value() As Integer
    ...
    End Property
    ...
    'this could be overloaded if needed
    Public Sub New(ByVal Value As Integer)
        _Value = Value
    End Sub
    '
    Public Shared Widening Operator CType(ByVal val As Integer) As GenericStat
        Return New GenericStat(val)
    End Operator
    '
    Public Shared Widening Operator CType(ByVal val As GenericStat) As Integer
        Return val.Value
    End Operator
End Class

所以現在

Dim MyObject as GenericStat
MyObject = 123

Dim Int as Integer
Int = MyObject   

兩者都沒有.Value引用,也沒有像myobject(1)這樣的索引器myobject(1)

不,這是從VB 7中明確刪除的。

當您擁有一長串默認屬性時,確切地知道將返回的內容很難。 bc都有Foo方法時, a.Foo(1)是指abFoo(1)還是abcFoo(1)

真正的踢球者是Set 通過刪除默認屬性,他們還可以刪除對象分配的Set關鍵字。

在此示例中,它會拉取對象,但不會將其轉換為整數。

Brian,我不明白為什么使用Widening Operator CType無法達到預期的效果。 您向我們展示的代碼可以使用。 但是,請注意隱式轉換。 他們通常不是一個好主意。

我一直在尋找類似問題的答案,在這個過程中我偶然發現了這個問題。 實際上,約翰的回答指出了我需要走的方向。 它也可能對原始問題有所幫助:

我的問題:我需要一些我可以像整數一樣使用的東西

Dim myVal as Integer
myVal = 15
If myVal = 15 then
  ...
End If

...等等......但我還需要其他東西

myVal.SomeReadOnlyProperty (as String)
myVal.SomeOtherReadOnlyProperty (as Integer)

(實際上那些只讀屬性也可以是方法......)
等...所以我真的需要一個對象

我在想Integer的擴展方法(@ _ @)......我不想走那條路......

我還想過將“ReadOnlyPropertyOracle”作為一個單獨的類編寫,並給它像方法一樣

GetSomeReadOnlyProperty(ByVal pVal as Integer) as String
GetSomeOtherReadOnlyProperty(ByVal pVal as Integer) as Integer

weeeell ....那本來有用,但看起來很可怕......

所以John's Hack和Brian MacKay關於運算符的評論:結合兩者,擴展/縮小轉換運算符(用於賦值)和比較運算符......以便進行比較。 這是我的代碼的一部分,它做我需要的:

'The first two give me the assignment operator like John suggested
Public Shared Widening Operator CType(ByVal val As Integer) As MySpecialIntType
    Return New MySpecialIntType(val)
End Operator

'As opposed to John's suggestion I think this should be Narrowing?
Public Shared Narrowing Operator CType(ByVal val As MySpecialIntType) As Integer
    Return val.Value
End Operator

'These two give me the comparison operator
'other operators can be added as needed
Public Shared Operator =(ByVal pSpecialTypeParameter As MySpecialIntType, ByVal pInt As Integer) As Boolean
    Return pSpecialTypeParameter.Value = pInt
End Operator

Public Shared Operator <>(ByVal pSpecialTypeParameter As MySpecialIntType, ByVal pInt As Integer) As Boolean
    Return pSpecialTypeParameter.Value <> pInt
End Operator

是的,這仍然是1-2個單行操作員定義,但大多數都是微不足道的,幾乎沒有錯誤的余地;-)所以這對我有用...

為了回答我自己的問題,運算符重載似乎是一個有趣的解決方案。

最后,它不適合。

我最終不得不添加大約17個1行方法,這意味着有很多錯誤的空間。 更重要的是你不能重載賦值運算符; =的重載僅用於相等測試。

所以即便如此,我也不能說:

Dim x as Integer = MyObject.Stats(Stat.Health) ...在這個例子中,它拉動對象,但不會將其轉換為整數,所以當然結果是異常。

我真正需要的是一個很好的老式默認財產,但我認為那些日子結束了。

嗨約翰你的回答非常有用! 我改變了任何類型的使用,謝謝。

Public Class GenericStat(Of Ttype)

Public Property Value As Ttype
'
Public Sub New()

End Sub
'
'this could be overloaded if needed
Public Sub New(ByVal Value As Ttype)
   _Value = Value
End Sub
'
Public Shared Widening Operator CType(ByVal val As Ttype) As GenericStat(Of Ttype)
   Return New GenericStat(Of Ttype)(val)
End Operator
'
Public Shared Widening Operator CType(ByVal val As GenericStat(Of Ttype)) As Ttype
   Return val.Value
End Operator

End Class

用法:

Dim MyInteger As GenericStat(Of Integer)
MyInteger = 123

Dim Int As Integer
Int = MyInteger

Dim MyString As GenericStat(Of String)
MyString = "MyValue"

Dim Str As String
Str = MyString

有一個DefaultProperty屬性,所以你的例子應該是正確的, 但這似乎是在Windows窗體desinger中使用的組件。

您可以覆蓋ToString方法以將Value作為字符串輸出,這樣當您執行Response.Write(MyObject)時,您將獲得相同的效果。

    Public Overrides Function ToString() As String
        Return Me.Value.ToString 
    End Function

[編輯]現在我更了解它,為什么不提供直接獲取所包含對象的值的方法。

Public Class MyClass
    Private m_Stats(100) As Stats  ' or some other collection'

    Public Property StatValue(ByVal stat_number As Integer) As _
        Integer
        Get
            Return m_Stats(stat_number)
        End Get
        Set(ByVal Value As Integer)
            m_Stats(stat_number) = Value
        End Set
    End Property
End Class

如果導入System.ComponentModel,仍可以使用該屬性。

正如其他人提到的,這並不理想,因為VB.Net更喜歡使用Default屬性。 當然,這附帶條件,這實際上沒有幫助(例如需要索引)。

但如果你使用

Imports System.ComponentModel

它允許您在類上使用該屬性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM