在.NET的早期,我相信有一个属性可以用类来指定一个默认属性。
根据我发现的一些文章,这似乎在某种程度上已经从框架中被淘汰,因为它有点令人困惑,我可以看到这是怎么回事。
还有,还有其他方法可以获得它提供的功能吗?
它看起来像这样:
<DefaultProperty("Value")> _
Public Class GenericStat
...
Public Property Value() As Integer
...
End Property
...
End Class
这允许你做Response.Write(MyObject)
而不是Response.Write(MyObject.Value)
...这不是一个非常笨重的例子,但在一些复杂的面向对象的上下文中它有点可怕。如果有更好的方法,请告诉我。
注意:我不是在寻找Default关键字,它只能用于带参数的属性。
答案 0 :(得分:29)
嗯,.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”。
答案 1 :(得分:9)
我发现你可以使用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)
答案 2 :(得分:5)
不,这是从VB 7中明确删除的。
当您拥有一长串默认属性时,确切地知道将返回的内容很难。当b
和c
都采用Foo
方法时,a.Foo(1)
是a.b.Foo(1)
还是a.b.c.Foo(1)
?
真正的踢球者是Set
。通过删除默认属性,他们还可以删除Set
关键字以进行对象分配。
答案 3 :(得分:5)
在此示例中,它会拉取对象,但不会将其转换为整数。
布赖恩,我不明白为什么使用Widening Operator CType
无法达到预期的效果。您向我们展示的代码可以使用。但是,请注意隐式转换。他们通常不是个好主意。
答案 4 :(得分:3)
我一直在寻找类似问题的答案,在这个过程中我偶然发现了这个问题。 实际上,约翰的回答指出了我需要走的方向。它也可能对原始问题有所帮助:
我的问题: 我需要一些我可以像整数一样使用的东西
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
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个单行操作员定义,但大多数都是微不足道的,几乎没有错误的余地;-)所以这对我有用......
答案 5 :(得分:2)
要回答我自己的问题,运算符重载似乎是一个有趣的解决方案。
最后,这不合适。
我最终不得不添加大约17个1行方法,这意味着有很多错误的空间。更重要的是你不能重载赋值运算符; =
的重载仅用于等式测试。
所以即使这样,我也不能说:
Dim x as Integer = MyObject.Stats(Stat.Health)
...在此示例中,它会拉取对象,但不会将其转换为整数,因此结果当然是异常。
我真正需要的是一个很好的老式默认属性,但我认为那些日子结束了。
答案 6 :(得分:1)
有一个DefaultProperty
属性,因此您的示例应该是正确的,但这似乎适用于Windows窗体设计器中使用的组件。
答案 7 :(得分:1)
您可以覆盖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
答案 8 :(得分: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
答案 9 :(得分:0)
如果导入System.ComponentModel,您仍然可以使用该属性。
正如其他人提到的,这并不理想,因为VB.Net更喜欢使用Default属性。当然,这带有条件,这并没有真正的帮助(例如需要索引)。
但是如果你使用
Imports System.ComponentModel
它允许您在班级上使用该属性。