【问题标题】:Overriding ReadOnly Property in a subclass to make it Read/Write (VB.NET or C#)覆盖子类中的 ReadOnly 属性以使其成为读/写(VB.NET 或 C#)
【发布时间】:2010-10-07 22:48:10
【问题描述】:

这在带有属性的 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

【问题讨论】:

  • 我不认为你可以在 VB.NET 中做到这一点(有人要证明我错了)如果它肯定是你自己的课程之一,你需要这样做的理由是什么这表明设计存在错误......或者接口可能会更好地使用?
  • 在我的情况下,该属性对于大多数子类型实际上是正确的,但有一个属性是可编辑的。现在我正在使用类型检查,但可覆盖的属性会更合适。

标签: c# vb.net inheritance properties readonly


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    为了解决 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
    

    【讨论】:

      【解决方案3】:

      确认 MrEdmuno 是正确的,因为您可以使用 Shadow。但是,您似乎无法直接隐藏标记为 MustInherit 的内容,因此您需要继承到一个类(父级 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
      

      【讨论】:

        【解决方案4】:

        鉴于您要完成的工作,以及您发布的示例代码,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 坚持认为,由于您要覆盖基类属性,因此您的整个属性必须与您要覆盖的属性具有相同的范围(在本例中为 public)。

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

        因此:

        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 方法,因为它们可以单独声明范围级别。

        【讨论】:

        • 可悲的是,这种烦恼也适用于 C#。
        • 自从我写了我的原始回复后,我得出的结论是,适当的补救措施是让基类拥有一个链接到抽象“get”方法的非虚拟只读属性。然后,可变派生类可以使用链接到上述“get”方法以及(可能是虚拟的)“set”方法的非虚拟属性来隐藏属性。
        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

          很遗憾,我这里没有 Visual Studio,所以我无法确认。

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

          【讨论】:

            【解决方案7】:

            考虑到我对 VB.NET 的了解很少...

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

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

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

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

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-09-14
              • 2010-12-02
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多