覆盖子类中的ReadOnly属性以使其成为读/写(VB.NET或C#)

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

在我下面的例子中,它不允许我编译ReadWriteChild 。 我想我可以让父读/写,然后让ReadOnlyChild的setter不做任何事情,但这似乎有点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不会让您这样做。

通常,您可以在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,因此您无法提供默认实现(即,它也是抽象的),这包括“获取”和“设置”轮廓,因此,无论哪个“整体” “您给这个抽象属性声明的范围,VB.NET将强制您将此范围用于派生类中的getter和setter。

在基类的属性上使用ReadOnly限定符将强制所有派生类和此属性的实现也是ReadOnly。 抛弃ReadOnly限定符仍然不起作用,因为您给abstract属性的任何范围都是必须应用于派生实现中的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上的私有作用域)。 这不会起作用,因为VB.NET坚持认为,因为你要覆盖基类属性,所以你的整个属性必须与你要覆盖的属性(在本例中为public)具有相同的范围。

尝试使基类的抽象属性受到保护也不会起作用,因为您需要在与基类中声明的作用域相同的级别(即受保护的)上实现该属性。 通常,在不使用特定的作用域级别覆盖基类的抽象定义时,可以为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 

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

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

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

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

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

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

另请注意,覆盖可以比它们覆盖的内容具有更高的可见性 – 因此您可以执行此操作:

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

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

确认MrEdmuno是否正确,因为您可以使用Shadow。 然而,看起来你不能直接遮住标记为MustInherit的东西,所以你需要inheritance到一个类(父2)…然后进入你的readonly(实际上考虑它你可能不需要使用阴影,如果你inheritance成class)

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

 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 

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

你有没有看过使用Shadows,这与在C#属性声明中说“new”一样有效。

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

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

您需要添加另一级别的层次结构; 遗憾的是,真正确定范围的唯一方法是使用嵌套类:

 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