2008-11-15 6 views
26

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

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

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

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

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

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

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

ответ

28

Ну, в .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 как «Item».

1

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

+0

Я нашел это, но, похоже, он не делает то, что я ищу. – 2008-11-15 23:44:57

+0

То есть я действительно пробовал это, и это, казалось, не имело никакого влияния. :) – 2008-11-15 23:52:15

+2

Да, DefaultProperty действительно полезен только для свойстваgrid, и это позволяет ему определить, отличается ли текущее значение от значения по умолчанию. – 2008-11-20 17:50:58

1

Вы можете переопределить метод 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 
+0

Интересная идея - если бы я мог заставить переменную выходить как целое или объект, это было бы еще лучше ... – 2008-11-16 00:01:47

+0

Response.Write собирается вызывать ToString на объекте в любом случае, когда он записывает его в поток ответов. – tvanfosson 2008-11-16 00:04:09

+0

Я вообще не делаю response.write - фактическое использование больше похоже: thisObject.stats (stat.health) .value, см.? некрасиво. – 2008-11-16 00:08:34

1

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

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

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

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

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

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

4

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

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

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

5

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

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

0

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

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

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

Imports System.ComponentModel

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

8

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

1

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

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 
2

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

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

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

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

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

Смежные вопросы