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



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

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

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

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

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

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

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

162   10  

10 ответов:

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

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

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

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

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

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

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

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

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

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

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

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

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

Вы можете переопределить метод ToString для вывода значения в виде строки, чтобы при выполнении ответа.Напишите (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

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

В конце концов, это было не очень хорошо.

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

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

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

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

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

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

Imports System.ComponentModel

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

    Ничего не найдено.

Добавить ответ:
Отменить.