Свойства по умолчанию в VB.NET? - PullRequest
29 голосов
/ 16 ноября 2008

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

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

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

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

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

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

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

Ответы [ 10 ]

29 голосов
/ 17 ноября 2008

Ну, .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.

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

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

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

9 голосов
/ 20 октября 2013

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

5 голосов
/ 18 ноября 2008

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

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

5 голосов
/ 18 ноября 2008

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

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

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

3 голосов
/ 21 августа 2014

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

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

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 .... Это бы сработало, но выглядело ужасно ...

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

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

2 голосов
/ 16 ноября 2008

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

В конце концов, это не совсем подходило.

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

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

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

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

1 голос
/ 17 апреля 2014

Привет, Джон, твой ответ был очень полезен! Я изменил для использования с любым типом, спасибо.

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
1 голос
/ 16 ноября 2008

Можно переопределить метод ToString для вывода значения в виде строки, чтобы при выполнении 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
1 голос
/ 16 ноября 2008

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

0 голосов
/ 10 ноября 2011

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

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

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

Imports System.ComponentModel

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...