6

这在带有属性的 VB.NET 中似乎是不可能的,因为属性语句本身必须描述它是否ReadOnly存在。

在下面的示例中,它不允许我进行ReadWriteChild编译。我想我可以让父级读/写,然后让 ReadOnlyChild 的设置器不做任何事情,但这似乎有点 hacky。在这种情况下,最好的选择似乎是放弃属性,转而使用 getter/setter 方法。

Public MustInherit Class Parent

    Public MustOverride ReadOnly Property Foo() As String

End Class

Public Class ReadOnlyChild
    Inherits Parent

    Public Overrides ReadOnly Property Foo() As String
        Get
            ' Get the Property
        End Get
    End Property

End Class

Public Class ReadWriteChild
    Inherits Parent

    Public Overrides Property Foo() As String
        Get
            ' Get the property.
        End Get
        Set(ByVal value As String)
           ' Set the property.
        End Set
    End Property

End Class
4

7 回答 7

6

鉴于您要完成的工作以及您发布的示例代码,VB.NET 不会让您这样做。

通常,您可以像这样在 VB.NET 中声明一个属性:

Public Class qwqwqw
  Public Property xyz() As String
      Get
          Return ""
      End Get
      Private Set(ByVal value As String)
          '
      End Set
  End Property
End Class

基本上将整个属性标记为公共的,但给 setter(或 getter)一个更严格的范围。

您的主要问题是 MustInherit (即抽象)基类。由于您在其中定义的属性被标记为 MustOverride,因此您不能提供默认实现(即它也是抽象的),因此这包括“Get”和“Set”大纲,因此,无论哪个“整体" 你给这个抽象属性声明的范围,VB.NET 将强制你在派生类中为 getter 和 setter 使用这个范围

在基类的属性上使用 ReadOnly 限定符将强制所有派生类和此属性的实现也为 ReadOnly。离开 ReadOnly 限定符仍然行不通,因为您赋予抽象属性的任何范围都将是您必须应用于派生实现中的 setter 和 getter 的范围。

例如:

Public MustInherit Class Parent
  Public MustOverride Property Foo() As String
End Class

Public Class ReadOnlyChild
  Inherits Parent

  Public Overrides Property Foo() As String
    Get
        '
    End Get
    Private Set(ByVal value As String)
        '
    End Set
  End Property
End Class

(注意 setter 上的 Private 范围)。这将不起作用,因为 VB.NET 坚持认为,由于您要覆盖基类属性,因此您的整个属性必须与您要覆盖的属性具有相同的范围(在本例中为公共)。

尝试使基类的抽象属性受保护也不起作用,因为您将需要在与基类中声明的相同范围级别(即受保护)中实现该属性。通常,当不使用特定范围级别覆盖基类的抽象定义时,您可以为 getter 或 setter 提供严格的范围级别,但不能为其提供限制较少的范围级别。

所以:

Public MustInherit Class Parent
  Protected MustOverride Property Foo() As String       
End Class

Public Class ReadOnlyChild
  Inherits Parent

  Protected Overrides Property Foo() As String
      Public Get
          '
      End Get
      Set(ByVal value As String)
          '
      End Set
  End Property
End Class

(注意 getter 的公共范围)。由于公共范围比受保护的整体属性范围限制更少,而且与基类的抽象属性声明中定义的范围级别不同,因此不起作用。

如果您的类的设计如您在问题中提到的那样,我个人会使用“java-style”getter 和 setter方法,因为它们可以使用自己的范围级别单独声明。

于 2009-02-16T21:09:32.377 回答
3

可能是一个远景......鉴于我对VB.NET的了解很少......

在 C# 中,您可以独立于属性指定属性访问器的可见性:

public virtual string Name
{
    get { ... }
    protected set { ... }
}

在此示例中,子类可以访问设置器,但其他类不能。

另请注意,覆盖可以比它们覆盖的内容具有更大的可见性 - 因此您可以这样做:

public overide string Name
{
    get { ... }
    public set { ... }
}

你能在 VB.NET 中做这样的事情吗?

于 2009-02-16T20:06:36.803 回答
2

确认 MrEdmuno 是正确的,因为您可以使用 Shadow。但是,您似乎无法直接遮蔽标记为 MustInherit 的东西,因此您需要继承到一个类(Parent 2)中……然后再继承到您的只读中(实际上考虑一下,如果您可能不需要使用阴影继承到一个类)

我认为我的评论问题仍然存在,你为什么需要这样做?如果它们是您自己的类,您会更好地修改它们,还是作为接口实现?

Public MustInherit Class Parent

    Public MustOverride ReadOnly Property Foo() As String

End Class

Public Class ReadOnlyChild
    Inherits Parent

    Public Overrides ReadOnly Property Foo() As String
        Get
            'Get the Property
            Return "Return"
        End Get
    End Property

End Class

Public Class Parent2
    Inherits Parent

    Public Overrides ReadOnly Property Foo() As String
        Get
            Return "Return 2"
        End Get
    End Property
End Class

Public Class ReadWriteChild
    Inherits Parent2

    Public Shadows Property Foo() As String
        Get
            '// Get the property.
            Return "2"
        End Get
        Set(ByVal value As String)
            '** Set something
        End Set
    End Property
于 2009-02-16T21:25:52.323 回答
0

不幸的是,我这里没有视觉工作室,所以我无法确认。

您是否看过使用阴影,这实际上与在 C# 属性声明中说“新”相同。

于 2009-02-16T21:08:54.330 回答
0

为了解决 Bevan 的建议,在 VB.NET 中,您可以将属性声明为具有公共 getter 和受保护的 setter,如下所示:

Private _ExpectedTotalRoyalties As Decimal

Public Property ExpectedTotalRoyalties() As Decimal
    Get
        Return _ExpectedTotalRoyalties
    End Get
    Protected Set(ByVal value As Decimal)
        If Not _ExpectedTotalRoyalties.Equals(value) Then
            _ExpectedTotalRoyalties = value
            SendPropertyChanged("ExpectedTotalRoyalties")
        End If
    End Set
End Property
于 2009-05-03T10:24:17.723 回答
0

不要尝试覆盖该属性,因为它不是虚拟的。覆盖 OnReadOnlyChanged 方法并在那里处理您的业务。祝你好运

于 2010-06-21T18:30:28.397 回答
0

您需要添加另一个层次结构;不幸的是,真正正确界定事物的唯一方法是使用嵌套类:

Public Class IntermediateClassForPrivateInheritanceOnly
  Inherits Parent
  Public Overrides ReadOnly Property Foo() As String
  ' etc.
  Private Sub New(whatever)
    MyBase.New(whatever)
  End Sub

  ' Most other stuff for the class goes here.

  Public Class ReadWriteChild
    Inherits IntermediateClassForPrivateInheritanceOnly
    Shadows Property Foo()
    ' etc.
    Public Sub New(whatever)
      MyBase.New(whatever)
    End Sub
  End Class
End Class

Public Class ReadWriteChild  ' Would use an alias, if such things existed
  Inherits IntermediateClassForPrivateInheritanceOnly
  Public Sub New(whatever)
    MyBase.New(whatever)
  End Sub
End Class
于 2010-12-20T19:47:55.707 回答