interfaces - polimorfismo c#
La clase VB.NET hereda una clase base e implementa un problema de interfaz(funciona en C#) (7)
Estoy intentando crear una clase en VB.NET que hereda una clase abstracta base 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.
Primero, aquí hay 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í está la versión de VB.NET que da un error de compilación:
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 que la clase base ( FooBase
) implemente la interfaz y añada Implements IFoo.Description
a la propiedad, todo está bien, pero no quiero que la clase base implemente la interfaz.
El error del compilador es:
La clase ''MyFoo'' debe implementar ''Descripción de la propiedad () como cadena'' para la interfaz ''IFoo''. La implementación de la propiedad debe tener especificadores ''ReadOnly'' o ''WriteOnly'' que coincidan.
¿Puede VB.NET no manejar esto, o necesito cambiar mi sintaxis en alguna parte para que esto funcione?
De una forma u otra, debe especificar los detalles de implementación de la interfaz IFoo.
¿Qué hay de esta simple 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
Este es un problema extraño y muestra claramente una diferencia entre los compiladores C # y VB.NET. Sugiero que implemente 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 aún tendrá metadatos que indiquen que de hecho implementa IFoo
.
¿Hay alguna razón específica para que la clase hija sea la que declare que implementa la interfaz?
Lo siento si llego tarde a la fiesta, y me disculpo si esta funcionalidad solo se introdujo en .NET 4, pero lo 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
No puedo comentar la 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
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.
Por lo tanto, la única manera de hacer que esto funcione sin implementar IFoo.Description
en FooBase
es declarar Description
Overridable
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
VB.NET no es compatible con la implementación implícita. También encontré este problema y tuve muchos problemas.
Cuando trabajas con clases generadas (entidades, etc.) donde tienes que declarar explícitamente Implements IFoo
, lo hace imposible en absoluto.
Por lo tanto , envié una conexión a Microsoft y espero que voten y la próxima versión de VB mejorará el compilador para que sea más inteligente.
Overridable
marcar su propiedad como Overridable
o MustOverride
en la clase base y luego puede MustOverride
en la clase secundaria:
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 @MA Hanin publicó. 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 X.Description? Usando el Overridable obtendrá la llamada a la clase secundaria mientras usa el método de Sobrecarga, recibirá la llamada a la clase base. Ninguno de los dos está bien o mal, solo es importante entender las consecuencias de la declaración. Usando el método de Sobrecarga, tiene que actualizar para obtener la implementación del niño:
Trace.WriteLine(DirectCast(X, MyFoo).Description)
Si solo llamas a MyBase.Description desde la clase de niños, la pregunta es discutible, pero si alguna vez cambias la definición de la clase de niños entonces solo necesitas asegurarte de que entiendes lo que está pasando.