2010-04-09 11 views
29

Estoy tratando de crear una clase en VB.NET que hereda de una clase base abstracta y también implementa una interfaz. La interfaz declara una propiedad de cadena llamada Descripción. La clase base contiene una propiedad de cadena llamada Descripción. La clase principal hereda la clase base e implementa la interfaz. La existencia de la propiedad Descripción en la clase base cumple los requisitos de interfaz. Esto funciona bien en C# pero causa problemas en VB.NET.clase VB.NET hereda una clase base e implementa un problema de interfaz (funciona en C#)

primer lugar, aquí es un ejemplo del código C# que funciona:

public interface IFoo 
{ 
    string Description { get; set; } 
} 

public abstract class FooBase 
{ 
    public string Description { get; set; } 
} 

public class MyFoo : FooBase, IFoo 
{ 
} 

Ahora aquí es la versión VB.NET que da un error del compilador:

Public Interface IFoo 
    Property Description() As String 
End Interface 

Public MustInherit Class FooBase 
    Private _Description As String 
    Public Property Description() As String 
     Get 
      Return _Description 
     End Get 
     Set(ByVal value As String) 
      _Description = value 
     End Set 
    End Property 
End Class 

Public Class MyFoo 
    Inherits FooBase 
    Implements IFoo 
End Class 

Si hago la base clase (FooBase) implementar la interfaz y añadir la Implements IFoo.Description a la propiedad todo es bueno, pero no quiero que la clase base para implementar la interfaz.

El error del compilador es:

Class 'MyFoo' must implement 'Property Description() As String' for interface 'IFoo'. Implementing property must have matching 'ReadOnly' or 'WriteOnly' specifiers.

Puede VB.NET no manejar esto, o tengo que cambiar mi sintaxis de un lugar para conseguir que esto funcione?

+0

que el código C# no puede compilar porque no implementa la Descripción de la clase abstracta. ¿Estás seguro de que realmente quieres tener una interfaz Y una base abstracta? –

+0

@gbogumil - La versión C# _describe_la compilación - la implementación de la interfaz está en la clase base. –

+1

Las respuestas a continuación responden a su pregunta - Personalmente creo que esta es una de las cosas más molestas cuando intento escribir código limpio en VB.net ... – Paddy

Respuesta

20

Usted necesidad de marcar su propiedad como Overridable o MustOverride en la clase base y luego se puede anular en la clase del niño:

Public MustInherit Class FooBase 
    Private _Description As String 
    Public Overridable Property Description() As String 
     Get 
      Return _Description 
     End Get 
     Set(ByVal value As String) 
      _Description = value 
     End Set 
    End Property 
End Class 

Public Class MyFoo 
    Inherits FooBase 
    Implements IFoo 
    Public Overrides Property Description() As String Implements IFoo.Description 
     Get 
      Return MyBase.Description 
     End Get 
     Set(ByVal value As String) 
      MyBase.Description = value 
     End Set 
    End Property 
End Class 

Editar Esto es en respuesta a lo que @ MAMÁ Hanin publicado. Ambas soluciones funcionan pero es importante entender las ramificaciones de cada una. Imagine el siguiente código:

Dim X As FooBase = New MyFoo() 
Trace.WriteLine(X.Description) 

¿Qué sale de la X.Description? Utilizando el Overridable obtendrá la llamada a la clase hija mientras se utiliza el método de sobrecarga que obtendrá la llamada a la clase base. Ninguno de los dos está bien o mal, solo es importante entender las consecuencias de la declaración. Utilizando el método de sobrecarga que tiene que hasta fundido para obtener la implementación del niño:

Trace.WriteLine(DirectCast(X, MyFoo).Description) 

Si acaba de llamar MyBase.Description de la clase hija la cuestión es discutible, pero si alguna vez cambia la definición del niño clase, entonces solo necesitas asegurarte de que entiendes lo que está pasando.

+0

Sr. Haas, me alegro de encontrarlo de nuevo en los temas de VB.NET :-) Estaba considerando esta solución también, pero decidí abandonarla y dejar la clase base "tal como está". Sin embargo, esta es una solución perfectamente válida. +1! –

+0

Me inclino a marcar esto como la respuesta, aunque esperaba que este no fuera el caso. Me hace sentir mal sabiendo que estoy anulando una propiedad base simplemente para llamar a la propiedad base que estoy anulando. Entiendo que esto debe ser una restricción (no lo llamaré una limitación) de VB.NET en el sentido de que la clase implementadora debe definir la propiedad contratada directamente dentro de la clase, incluso si una clase base cumple con el contrato. Quizás VB.NET finalmente implementará implícitamente un miembro sin requerir la palabra clave 'Implements'. –

+0

Si no desea sobrescribir, use Sobrecargas (vea mi publicación). El mecanismo de implementación de interfaz de VB.NET es bastante flexible en algunos aspectos y no flexible de otras maneras. La propiedad de implementación no tiene que tener el mismo nivel de acceso, nombre de método o nombre de argumento. Debido a este mecanismo flexible, las implementaciones de interfaz implícitas tuvieron que ser descuidadas. –

11

De un modo u otro, debe especificar los detalles de implementación de la interfaz IFoo.

¿Qué pasa con esta sencilla opción?

Public Class MyFoo 
    Inherits FooBase 
    Implements IFoo 
    Overloads Property Description() As String Implements IFoo.Description 
     Get 
      Return MyBase.Description 
     End Get 
     Set(ByVal value As String) 
      MyBase.Description = value 
     End Set 
    End Property 
End Class 
+0

Ha pasado un tiempo desde que se escribió esta respuesta, pero solo quería decir que esta es la solución que implementé pero NDepend arroja un error crítico al decir 'No ocultar los métodos de la clase base'.Molesto – Phil

0

Este es un tema extraño y que muestra claramente la diferencia entre el C# y VB.NET compiladores. Sugeriría implementar la interfaz en la clase base abstracta, ya que esto hará que el compilador de VB.NET esté contento y, en el momento de la ejecución, su clase secundaria todavía tendrá metadatos que indiquen que de hecho implementa IFoo.

¿Hay alguna razón específica que la clase del niño debe ser el que declarar que implementa la interfaz?

+0

buena pregunta. ¿Por qué no pones 'Implements IFoo' dentro de FooBase? –

4

VB requiere que la propiedad de implementación declare la implementación. Esto se debe a lo que realmente considero una buena característica de VB que a veces extraño en C#, que puede cambiar el nombre del miembro que implementa el miembro de la interfaz.

Así, la única manera de hacer este trabajo sin implementar en IFoo.DescriptionFooBase es declarar DescriptionOverridable y luego definir MyFoo como:

Public Class MyFoo 
    Inherits FooBase 
    Implements IFoo 

    Public Overrides Property Description() As String Implements IFoo.Description 
     Get 
      Return MyBase.Description 
     End Get 
     Set(ByVal value As String) 
      MyBase.Description = value 
     End Set 
    End Property 
End Class 
+0

También puede implementar explícitamente los miembros de la interfaz en C#, creo, lo que le permitiría cambiar el nombre de los miembros en su clase de implementación. –

+0

@MikeCole Los miembros de la interfaz implementados explícitamente en C# tendrán el mismo nombre que en la interfaz. Siempre puede agregar miembros adicionales en su clase concreta que llamen a la implementación explícita, convirtiendo 'this' en el tipo de interfaz, pero eso no le compra nada cuando trabaja con la interfaz. – Jay

+0

Oh, ¿de verdad? Pensé que explícitamente declaraba que te permitiría tener diferentes nombres. Supongo que nunca lo intenté. –

2

VB.NET no es compatible con la ejecución implícita. También encontré este problema y tuve muchos problemas.

Cuando trabaja con clases generadas (entidades, etc.) donde tiene que declarar explícitamente Implements IFoo, lo hace imposible en absoluto.

Por lo tanto, I submitted a connection to Microsoft y espero que voten y la próxima versión de VB mejorarán el compilador para ser más inteligentes.

+2

Subí tu conexión de Microsoft. –

3

Lo siento si llego tarde a la fiesta, y disculpas también si esta funcionalidad sólo se ha introducido en .NET 4, pero el siguiente es posible (ahora)

Public Interface IFoo 
    Property Description() As String 
End Interface 

Public MustInherit Class FooBase 
    Implements IFoo 

    Public MustOverride Property Description As String Implements IFoo.Description 
End Class 

Public Class MyFoo 
    Inherits FooBase 

    Private _description As String 

    Public Overrides Property Description As String 
     Get 
      Return _description 
     End Get 
     Set(value As String) 
      _description = value 
     End Set 
    End Property 
End Class 
1

que no puedo comentar sobre el Respuesta de MA Hanin debido a mi representante, pero recomendaría una pequeña modificación para evitar las advertencias del compilador sobre la ocultación de métodos base, suponiendo que no desea o no puede anular la propiedad en la clase base.

Public Class MyFoo 
    Inherits FooBase 
    Implements IFoo 
    Private Property IFoo_Description() As String Implements IFoo.Description 
     Get 
      Return Me.Description 
     End Get 
     Set(ByVal value As String) 
      Me.Description = value 
     End Set 
    End Property 
End Class 
Cuestiones relacionadas