【问题标题】:Why cant a readonly property be overrided with a read/write property in .net? [duplicate]为什么不能用 .net 中的读/写属性覆盖只读属性? [复制]
【发布时间】:2011-07-21 08:26:02
【问题描述】:

从概念上讲,派生类似乎应该能够用读写属性覆盖只读属性。为什么这不可能?

Public Class Base

    Protected _name As String
    Public Overridable ReadOnly Property Name() As String
        Get
            return _name
        End Get
    End Property

End Class

Public Class Derived
    Inherits Base

    Public Overrides Property Name() As String
        Get
            Return MyBase.Name
        End Get
        Set(ByVal value As String)
            _name = value
        End Set
    End Property

End Class

【问题讨论】:

  • 我有一个更好的问题:为什么 SUBclass 能够在其基类中设置只读属性???
  • 好问题,但只能由从事该语言的 OO 实现设计的微软人员来回答。
  • 那么,我不应该这样做吗?
  • @Brian Driscol:对于接口或抽象基类提供只读属性以及派生接口或类提供可变版本实际上是一个非常好的模式。例如,如果使用 IList 完成了该操作,则需要读取(但不需要写入)传入的类似数组的 Animal 集合的类将能够接受 List。顺便说一句,拥有一个不可变类也很好,它分别从同一个基类派生而来,只能通过其构造函数设置。

标签: .net vb.net


【解决方案1】:

我不同意,更改基类属性的 ReadOnly 访问权限似乎是无稽之谈。

VBs ReadOnly 的规则是经过仔细定义的: http://msdn.microsoft.com/en-us/library/z2b2c2ka.aspx#Y300

基类作者可以将属性标记为只读。

您不会知道更改属性值的后果是什么。

【讨论】:

  • 在语义上定义为 IMMUTABLE 的类不应有可变的子类(也不应在其程序集之外继承),但只读并不意味着不可变。在许多情况下,让一个方法接受其他可能是可变或不可变的对象可能很有用,而不关心哪个;做到这一点的正确方法是拥有一个只读(可能是抽象的)基类,并从中派生可变和不可变类。
【解决方案2】:

属性是具有访问器方法的“构造”。

当您将 Overridable 关键字放在属性中时,它会应用于其访问器。

对于只读属性,您只有get 访问器,所以它是Overridable。

在您的派生类中,您将属性标记为Overrides,但您可以仅覆盖get 访问器,因为它是唯一的Overridable 访问器。如果您随后包含一个 set 访问器,则它不会覆盖任何内容,因此您会收到该错误。

我想这在 IL 中是可能的,但在 VB.NET 或 C# 中是不可能的。

你可以做的是隐藏一个子类定义,但是关于多态调度,你不会有与覆盖相同的行为:

Public Class Derived
    Inherits Base

    Public Shadows Property Name() As String
        Get
            Return MyBase.Name
        End Get
        Set(ByVal value As String)
            _name = value
        End Set
    End Property

End Class

或者你可以在基类中提供一个空的setter(或者一个抛出NotSupportedException的setter),在子类中就是Overridable。

或者您可以在属性定义之外提供另一种方法来进行设置:

Public Sub SetName(ByVal value As String)
    _name = value
End Sub

【讨论】:

  • 这在 C# 中实际上是可能的。我需要使用它的唯一一次是如果我声明一个具有只读属性的接口,但希望实现类具有该属性是可读写的。在 VB 中,即使使用接口也无法做到这一点,这很烦人。
  • 在带有基类的 C# 中是不可能的。但是,是的,接口是可能的。
  • 是的,你是对的。我是这么认为的,因为它适用于接口,而我只需要使用接口。
  • VB现在可以在构造函数中设置只读属性,并覆盖接口只读属性添加一个setter。
【解决方案3】:

我不认为你真的应该这样做——VB.NET 语言根本不允许这样做。我猜测为什么是因为接口上的属性使用ReadOnly 修饰符来确定它是否应该有一个Getter / Setter,而不是一个getter / setter。您可以得到的最接近的方法是将基础更改为具有引发异常的设置器,并且派生类覆盖它:

Public Class Base
    Protected _name As String
    Public Overridable Property Name() As String
        Get
            Return _name
        End Get

        Set(ByVal value As String)
            Throw New Exception("Can't do it")
        End Set
    End Property
End Class

Public Class Derived
    Inherits Base
    Public Overrides Property Name() As String
        Get
            Return _name
        End Get
        Set(ByVal value As String)
            _name = value
        End Set
    End Property
End Class

【讨论】:

    猜你喜欢
    • 2010-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-22
    • 1970-01-01
    • 1970-01-01
    • 2013-03-05
    相关资源
    最近更新 更多