Подтвердить что ты не робот

Свойства по умолчанию в VB.NET?

В начале .NET, я верить был атрибут, который вы могли бы украсить классом, чтобы указать свойство по умолчанию.

В соответствии с некоторыми статьями, которые я нашел, в какой-то момент это, похоже, вырвалось из фреймворка, потому что это было немного запутанно, и я вижу, как это происходит.

Тем не менее, есть ли другой способ получить предоставленную функциональность?

Это выглядело примерно так:

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

Это позволило вам сделать Response.Write(MyObject) вместо Response.Write(MyObject.Value)... Это не ужасно неуклюжий пример, но в некоторых сложных объектно-ориентированных контекстах он становится немного отвратительным. Пожалуйста, дайте мне знать, если есть лучший способ.

Примечание. Я не ищу ключевое слово Default, которое можно использовать только для свойств, которые принимают параметр.

4b9b3361

Ответ 1

Ну, в .NET Framework есть понятие члена по умолчанию. Ключевыми компонентами являются класс 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.

С# имеет точные правила, но не допускает такой же гибкости. Вероятно, вы видели индексатора раньше:

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

Этот код также позволяет компилятору вывести атрибут [DefaultMember]. Именованное свойство в этом атрибуте - "Item". И поэтому вы видите, что индексщик документально и индексирован в библиотеке MSDN как "Item".

Ответ 2

Я обнаружил, что вы можете сделать то, что хотел сделать оригинальный плакат, используя 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)

Ответ 3

В этом примере он вытягивает объект, но не преобразовывает его в целое.

Брайан, я не понимаю, почему ваш желаемый эффект не может быть достигнут с помощью Widening Operator CType. Код, который вы нам показали, можно заставить работать. Однако остерегайтесь неявных преобразований. Обычно это не очень хорошая идея.

Ответ 4

Нет, это было явно удалено из VB 7.

Если у вас длинная цепочка свойств по умолчанию, то точно знать, что будет возвращено, сложно. Если b и c имеют метод Foo, то a.Foo(1) означает a.b.Foo(1) или a.b.c.Foo(1)?

Настоящий кикер был Set. Отбрасывая свойства по умолчанию, они также могли отбросить ключевое слово Set для назначения объекта.

Ответ 5

Существует атрибут DefaultProperty, поэтому ваш пример должен быть правильным, но это похоже на компоненты, которые используются в Windows Forms desinger.

Ответ 6

Вы можете переопределить метод ToString для вывода значения как строки, так что когда вы выполняете Response.Write(MyObject), вы получите тот же эффект.

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

[EDIT] Теперь, когда я понимаю это лучше, почему бы просто не дать способ напрямую получить значения содержащихся объектов.

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

Ответ 7

Чтобы ответить на мой собственный вопрос, перегрузка операторов показалась здесь интересным решением.

В конце концов, это было не очень удобно.

В итоге мне пришлось добавить около 17 1-строчных методов, что означало много места для ошибок. Более важно то, что вы не можете перегрузить оператор присваивания; перегрузка для = предназначена только для тестирования равенства.

Так что даже с этим я не могу сказать:

Dim x as Integer = MyObject.Stats(Stat.Health)... В этом примере он вытягивает объект, но не преобразует его в целое число, поэтому, конечно, результат является исключением.

Мне действительно нужна хорошая старомодная собственность по умолчанию, но я думаю, что эти дни закончились.

Ответ 8

Привет, Джон, ваш ответ был очень полезен! Я изменил для использования с любым типом, спасибо.
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

Ответ 9

Я искал ответ на подобную проблему, и в процессе я наткнулся на это здесь. На самом деле Джон ответил мне в направлении, в котором мне нужно было идти. И это может помочь и с исходным вопросом:

Моя проблема: Мне нужно что-то, что я мог бы использовать так же, как Integer

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

... и так далее... Однако мне нужны были и другие вещи.

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

(на самом деле эти readonly Properties также могут быть методами...)
и т.д. Поэтому мне действительно нужен объект

Я думал о методах расширения для Integer (@_ @)... Я не хотел идти по этой дороге...

Я также думал о написании "ReadOnlyPropertyOracle" как отдельного класса и давал ему методы вроде

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

weeeell.... Это сработало бы, но выглядело ужасно...

Итак, Джон Харк и Брайан Маккей прокомментировали оператора: Сочетание как операторов расширения/сужения преобразования (для присвоения), так и операторов сравнения для... хорошо сравнения. Вот часть моего кода, и он делает то, что мне нужно:

'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 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 десятка однолинейных определений операторов, но большинство из них тривиально с небольшим количеством места для ошибки;-) Так что это работает для меня...

Ответ 10

Вы можете использовать этот атрибут, если импортируете System.ComponentModel.

Как уже упоминалось, это не идеально, поскольку VB.Net предпочитает использовать атрибут Default. Конечно, это связано с условиями, которые на самом деле не помогают (например, для индекса).

Но если вы используете

Imports System.ComponentModel

он позволяет использовать атрибут в вашем классе.