2009-02-16 11 views
6

Esto no parece posible en VB.NET con propiedades ya que la declaración de propiedad en sí misma debe describir si es ReadOnly o no.Anulación de ReadOnly Propiedad en una subclase para hacerla leer/escribir (VB.NET o C#)

En mi ejemplo a continuación, no me deja hacer la compilación ReadWriteChild. Supongo que podría hacer que el padre lea/escriba, y luego hacer que el setter de ReadOnlyChild no haga nada, pero parece una especie de hacky. La mejor alternativa parece ser abandonar las propiedades a favor de los métodos getter/setter en este caso.

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 
+0

No creo que se puede hacer eso en VB.NET (que alguien está a punto de demostrar que estoy equivocado) ¿cuál es su razonamiento para necesitar para hacerlo así, si es una de sus propias clases, seguramente esto indica un error en el diseño ... ¿o quizás las interfaces se habrían usado más? – spacemonkeys

+0

En mi caso, la propiedad es efectivamente cierta para la mayoría de los subtipos, pero hay una donde dicha propiedad es editable. En este momento estoy usando comprobaciones de tipo, pero una propiedad invalidada sería más apropiada. –

Respuesta

6

Dado lo que está tratando de lograr, y con el código de muestra que publicó, VB.NET no le permitirá hacerlo.

Ordinariamente, se puede declarar una propiedad en VB.NET, así:

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

marca Básicamente, la propiedad en general como públicos, pero dando un alcance más restrictiva a la incubadora (o captador).

El problema principal en su caso es la clase base MustInherit (es decir, abstracta). Como la propiedad que está definiendo allí está marcada como MustOverride, no puede proporcionar una implementación predeterminada (es decir, también es abstracta), y esto incluye los contornos "Obtener" y "Establecer", por lo tanto, cualquiera que sea el "general". "alcance que le da a esta declaración de propiedad abstracta, VB.NET le obligará a usar este alcance para ambos los getters y setters dentro de las clases derivadas.

Tener el calificador ReadOnly en la propiedad de la clase base obligará a todas las clases derivadas y las implementaciones de esta propiedad a ser solo ReadOnly. Dejar el calificador ReadOnly aún no funcionará, ya que cualquier alcance que otorgue a la propiedad abstracta será el alcance que debe aplicar tanto a los establecedores como a los getters en las implementaciones derivadas.

Por ejemplo:

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 

(Nota del alcance privado en la incubadora). Esto no funcionará, ya que VB.NET insiste en que, dado que está anulando la propiedad de las clases base, toda su propiedad debe tener el mismo alcance que la propiedad que está anulando (en este caso, pública).

Intentar proteger la propiedad abstracta de la clase base tampoco funcionará, ya que entonces se le solicitará que implemente la propiedad en el mismo nivel de alcance que se ha declarado en su clase base (es decir, protegida). Normalmente, cuando no anula la definición abstracta de una clase base con un nivel de ámbito específico, puede otorgarle a un getter 0 un más nivel de alcance restrictivo, pero no puede otorgarle un nivel de alcance restrictivo menos.

Por lo tanto:

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 

(Nota del alcance público en el captador). Tampoco funciona debido a que el alcance público es menos restrictivo que el alcance general de la propiedad protegido y, además, no tiene el mismo nivel de alcance definido en la declaración de propiedad abstracta de la clase base.

Si el diseño de sus clases es como usted menciona en su pregunta, yo personalmente, iría con un captador "al estilo de Java" y colocador métodos, ya que entonces se pueden declarar por separado con sus propios niveles de alcance.

+0

Lamentablemente, esta molestia también se aplica a C#. –

+0

Desde que escribí mi respuesta original, llegué a la conclusión de que el remedio adecuado es que la clase base tenga una propiedad de solo lectura no virtual que encadena a un método abstracto de "obtener". Una clase derivada mutable puede sombrear la propiedad con una no virtual que encadena al método "get" mencionado anteriormente, así como un método "set" (posiblemente virtual). – supercat

3

podría ser una posibilidad remota ... dado que mi conocimiento de VB.NET es mínima ...

En C# puede especificar la visibilidad de un acceso de propiedad independiente de la propiedad:

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

En este ejemplo, las clases secundarias pueden acceder al ajustador, pero otras clases no pueden.

También tenga en cuenta que las anulaciones pueden tener una mayor visibilidad de lo que anulan - por lo que se puede hacer esto:

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

Podría hacer algo como esto en VB.NET?

0

Desafortunadamente no tengo Visual Studio aquí, así que no puedo confirmarlo.

Ha mirado el uso de Sombras, esto es realmente lo mismo que decir "nuevo" en la declaración de propiedad de C#.

2

Confirme que MrEdmuno tiene razón en cuanto a que puede usar Shadow. Sin embargo, parece que no se puede sombrear directamente algo que está marcado como MustInherit, por lo que debe heredar en una clase (Parent 2) ... luego en su readonly (de hecho, pensando en ello, probablemente no necesite usar sombras si heredar en una clase)

Creo que mi pregunta de comentario sigue en pie, ¿por qué es necesario hacer esto? Si son sus propias clases, ¿sería mejor modificarlas o implementarlas como interfaz?

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 
0

Para hacer frente a lo que sugirió Bevan, en VB.NET se puede declarar una propiedad como tener un captador público y un colocador protegida, de la siguiente manera:

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 
0

No trate de reemplazar la propiedad ya no es virtual Reemplace los métodos OnReadOnlyChanged y maneje su negocio allí. Buena suerte

0

Necesita agregar otro nivel de jerarquía; Por desgracia, la única manera de realmente alcance cosas correctamente es utilizar clases anidadas:

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 
Cuestiones relacionadas