VB.NET 中的默认属性?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/293215/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Default properties in VB.NET?
提问by Brian MacKay
In the early days of .NET, I believethere was an attribute you could decorate a class with to specify a default property.
在 .NET 的早期,我相信有一个属性可以用来装饰类以指定默认属性。
According to some articles I've found, this appears to have been yanked from the framework at some point, because it was a little confusing, and I can see how that is the case.
根据我发现的一些文章,这似乎在某个时候从框架中删除了,因为它有点令人困惑,我可以看到情况如何。
Still, is there another way to get the functionality it provided?
还有其他方法可以获得它提供的功能吗?
It looked something like this:
它看起来像这样:
<DefaultProperty("Value")> _
Public Class GenericStat
...
Public Property Value() As Integer
...
End Property
...
End Class
This allowed you to do Response.Write(MyObject)instead of Response.Write(MyObject.Value)... This is not a terribly clunky example, but in some complex object-oriented contexts it gets a little hideous. Please let me know if there is a better way.
这允许你做Response.Write(MyObject)而不是Response.Write(MyObject.Value)......这不是一个非常笨重的例子,但在一些复杂的面向对象的上下文中它变得有点可怕。请让我知道是否有更好的方法。
Note:I am not looking for the Default keyword, which can only be used on properties that take a parameter.
注意:我不是在寻找 Default 关键字,它只能用于带参数的属性。
回答by Hans Passant
Well, the .NET framework does have a notion of a default member. Key ingredients are the DefaultMemberAttribute class and Type.GetDefaultMembers(). In VB.NET, specifying the default member is part of the language syntax:
嗯,.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
Use it like this:
像这样使用它:
Sub Main()
Dim s As New Sample
Console.WriteLine(s(42))
Console.ReadLine()
End Sub
The compiler implements this by emitting [DefaultMember] automatically. This however has a restriction, the property must have an index argument, specifically to avoid the syntax ambiguity. This restriction is not enforced when specifying the attribute explicitly:
编译器通过自动发出 [DefaultMember] 来实现这一点。然而,这有一个限制,该属性必须有一个索引参数,特别是为了避免语法歧义。明确指定属性时,不会强制执行此限制:
<System.Reflection.DefaultMember("AnotherTest")> _
Public Class Sample
Public ReadOnly Property AnotherTest() As Integer
Get
Return 42
End Get
End Property
End Class
But that default member would only be accessible as a default by a language that allows such syntax. For which I don't know an example in .NET, this was used back in the COM days, like VB6. Also the core reason behind VB6 having the Set keyword, it solves the ambiguity and states "I mean the object, not the object's default property". Very painful syntax detail for many beginning Visual Basic programmers back then.
但是该默认成员只能作为默认成员被允许这种语法的语言访问。我不知道 .NET 中的示例,这在 COM 时代就已使用,例如 VB6。同样是 VB6 具有 Set 关键字的核心原因,它解决了歧义并声明“我的意思是对象,而不是对象的默认属性”。对于当时许多初学 Visual Basic 的程序员来说,非常痛苦的语法细节。
C# has the exact same rules, but doesn't allow the same kind of flexibility. You've probably seen the indexer before:
C# 具有完全相同的规则,但不允许具有相同的灵活性。您之前可能已经看过索引器:
public class Sample {
public int this[int index] {
get { return index; }
}
}
This code also makes the compiler output the [DefaultMember] attribute. The named property in that attribute is "Item". And that's why you see the indexer documented and indexed in the MSDN Library as "Item".
此代码还使编译器输出 [DefaultMember] 属性。该属性中的命名属性是“Item”。这就是为什么您会看到索引器在 MSDN 库中记录和索引为“项目”。
回答by John
I've found that you can do exactly what the original poster wanted using Widening Operator CTypeThis was mentioned above but without much detail, so I entirely missed it as I was trying to find an answer to this question. This methodology doesn't define a default property, per se, but it achieves the same result.
我发现您可以使用Widening Operator CType上面提到的 This来完成原始海报想要做的事情,但没有太多细节,所以我在试图找到这个问题的答案时完全错过了它。这种方法本身并没有定义默认属性,但它实现了相同的结果。
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
So now
所以现在
Dim MyObject as GenericStat
MyObject = 123
and
和
Dim Int as Integer
Int = MyObject
both work without the .Valuereference and without an indexer such as myobject(1)
两者都可以在没有.Value参考和索引器的情况下工作,例如myobject(1)
回答by Jonathan Allen
No, that was explicitly removed from VB 7.
不,这已从 VB 7 中明确删除。
When you have a long chain of default properties, knowing exactly what will be returned is hard. When both band chave a Foomethod, does a.Foo(1)mean a.b.Foo(1)or a.b.c.Foo(1)?
当您拥有一长串默认属性时,很难确切知道将返回什么。当b和c都有一个Foo方法时,是a.Foo(1)指a.b.Foo(1)还是a.b.c.Foo(1)?
The real kicker was Set. By dropping default properties, they were also able to drop the Setkeyword for object assignment.
真正的踢球者是Set。通过删除默认属性,他们还能够删除Set对象分配的关键字。
回答by Konrad Rudolph
In this example it pulls the object, but does not convert it to an integer.
在此示例中,它拉动对象,但不会将其转换为整数。
Brian, I don't see why your desired effect cannot be achieved using a Widening Operator CType. The code you showed us canbe made to work. However, beware of implicit conversions. They're generally nota good idea.
布莱恩,我不明白为什么使用Widening Operator CType. 您向我们展示的代码可以工作。但是,请注意隐式转换。它们通常不是一个好主意。
回答by Marko Pareigis
I've been looking for an answer to a similar problem and in the process I stumbled across this here. Actually John's answer pointed me into the direction I needed to go. And it might help with the original question as well:
我一直在寻找类似问题的答案,在此过程中我在这里偶然发现了这个问题。实际上,约翰的回答为我指明了我需要去的方向。它也可能有助于解决原始问题:
My Problem: I needed something that I could use just like an Integer
我的问题:我需要一些可以像整数一样使用的东西
Dim myVal as Integer
myVal = 15
If myVal = 15 then
...
End If
...and so on... However I needed additional things as well
......等等......但是我还需要额外的东西
myVal.SomeReadOnlyProperty (as String)
myVal.SomeOtherReadOnlyProperty (as Integer)
(actually those readonly Properties could be Methods as well ...)
etc... So I really needed an Object
(实际上那些只读属性也可以是方法......)
等等......所以我真的需要一个对象
I was thinking of extension methods for Integer ( @ _ @ ) ... I didn't want to go down that road ...
我正在考虑 Integer (@_@) 的扩展方法......我不想走那条路......
I also thought of writing a "ReadOnlyPropertyOracle" as a separate class and give it Methods like
我也想过写一个“ReadOnlyPropertyOracle”作为一个单独的类,并给它类似的方法
GetSomeReadOnlyProperty(ByVal pVal as Integer) as String
GetSomeOtherReadOnlyProperty(ByVal pVal as Integer) as Integer
weeeell .... That would have worked but looked gruesome ...
weeeell .... 那会奏效,但看起来很可怕......
So in came John's Hack and Brian MacKay's comment about operators: Combining both, widening/narrowing conversion operators (for assignment) and comparison operators for ... well comparision. Here is part of my code and it does what I need:
因此,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
Yes, this will still be 1-2 dozen one-line operator definitions but most of them are trivial with little room for error ;-) So this works for me...
是的,这仍然是 1-2 打单行运算符定义,但其中大多数都是微不足道的,几乎没有容错空间 ;-) 所以这对我有用......
回答by Brian MacKay
To answer my own question, operator overloading seemed to be an interesting solution here.
为了回答我自己的问题,运算符重载在这里似乎是一个有趣的解决方案。
In the end, it wasn't a good fit.
最后,这不是一个合适的人选。
I ended up having to add in about 17 1-line methods, which meant lots of room for bugs. More important is that you can't overload the assignment operator; the overload for =is for equality testing only.
我最终不得不添加大约 17 个 1 行方法,这意味着存在大量错误空间。更重要的是你不能重载赋值运算符;for 的重载=仅用于相等性测试。
So even with this, I can't say:
所以即使这样,我也不能说:
Dim x as Integer = MyObject.Stats(Stat.Health)...In this example it pulls the object, but does not convert it to an integer, so of course the result is an exception.
Dim x as Integer = MyObject.Stats(Stat.Health)...在这个例子中它拉取对象,但没有将其转换为整数,所以结果当然是一个例外。
What I really need is a good old fashioned default property, but I think those days are over.
我真正需要的是一个很好的老式默认属性,但我认为那些日子已经结束了。
回答by Vinicius
Hi John your answer was very useful! I changed for use with any type, thanks.
嗨,约翰,您的回答非常有用!我改变了使用任何类型,谢谢。
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
And the usage:
以及用法:
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
回答by hangy
There is a DefaultPropertyattribute so your example should be correct, butthis seems to be for components which are used in the Windows Forms desinger.
有一个DefaultProperty属性,因此您的示例应该是正确的,但这似乎适用于 Windows 窗体设计器中使用的组件。
回答by tvanfosson
You could override the ToString method to output Value as a string so that when you do Response.Write(MyObject), you get the same effect.
您可以覆盖 ToString 方法以将 Value 输出为字符串,以便在执行 Response.Write(MyObject) 时获得相同的效果。
Public Overrides Function ToString() As String
Return Me.Value.ToString
End Function
[EDIT] Now that I understand it better, why not just provide a way to get directly at the values of the contained objects.
[编辑] 现在我对它有了更好的理解,为什么不提供一种直接获取所包含对象的值的方法。
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
回答by Richard
You can still use the attribute if you import System.ComponentModel.
如果您导入 System.ComponentModel,您仍然可以使用该属性。
As others mentioned, this is not ideal since VB.Net prefers that you use the Default attribute. Of course, that comes with conditions, which doesn't really help (requiring an index, for example).
正如其他人提到的,这并不理想,因为 VB.Net 更喜欢您使用默认属性。当然,这附带条件,这并没有真正的帮助(例如,需要索引)。
But if you use
但是如果你使用
Imports System.ComponentModel
Imports System.ComponentModel
it allows you to use the attribute on your class.
它允许您在类上使用该属性。

