Класс VB.NET наследует базовый класс и реализует проблему с интерфейсом (работает на С#)
Я пытаюсь создать класс в VB.NET, который наследует базовый абстрактный класс, а также реализует интерфейс. Интерфейс объявляет свойство string, называемое Описание. Базовый класс содержит свойство string, называемое Описание. Основной класс наследует базовый класс и реализует интерфейс. Существование свойства Description в базовом классе соответствует требованиям интерфейса. Это отлично работает на С#, но вызывает проблемы в VB.NET.
Во-первых, вот пример кода С#, который работает:
public interface IFoo
{
string Description { get; set; }
}
public abstract class FooBase
{
public string Description { get; set; }
}
public class MyFoo : FooBase, IFoo
{
}
Теперь вот версия VB.NET, которая дает ошибку компилятора:
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
Если я создаю базовый класс (FooBase
), реализую интерфейс и добавляю Implements IFoo.Description
к свойству, все это хорошо, но я не хочу, чтобы базовый класс реализовал интерфейс.
Ошибка компилятора:
Класс 'MyFoo' должен реализовать 'Property Description() As String' для интерфейса 'IFoo'. У реализации свойства должны быть соответствующие спецификации ReadOnly или WriteOnly.
Может ли VB.NET не обрабатывать это, или мне нужно изменить синтаксис где-нибудь, чтобы заставить это работать?
Ответы
Ответ 1
Вам нужно пометить ваше свойство как Overridable
или MustOverride
в базовом классе, а затем вы можете переопределить его в дочернем классе:
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
Edit
Это в ответ на то, что @M.A. Ханин отправил. Оба наших решения работают, но важно понимать последствия каждого из них. Представьте следующий код:
Dim X As FooBase = New MyFoo()
Trace.WriteLine(X.Description)
Что из X.Description? Используя Overridable, вы получите вызов дочернего класса, используя метод Overload, и получите вызов базового класса. Ни то, ни другое неправильно, просто важно понять последствия декларации. Используя метод перегрузки, вы должны выполнить кастинг, чтобы получить реализацию ребенка:
Trace.WriteLine(DirectCast(X, MyFoo).Description)
Если вы просто вызываете MyBase.Description из дочернего класса, вопрос спорный, но если вы когда-либо измените определение дочернего класса, вам просто нужно убедиться, что вы понимаете, что происходит.
Ответ 2
Так или иначе, вы должны указать детали реализации интерфейса IFoo.
Как насчет этой простой опции?
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
Ответ 3
VB требует, чтобы свойство реализации объявляло реализацию. Это из-за того, что я действительно считаю приятной особенностью VB, которую я иногда пропускаю на С#, - что вы можете переименовать элемент, который реализует член интерфейса.
Таким образом, единственный способ сделать эту работу без реализации IFoo.Description
в FooBase
- объявить Description
Overridable
, а затем определить MyFoo
как:
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
Ответ 4
Извините, если я опаздываю на вечеринку и тоже извиняюсь, если эта функция была введена только в .NET 4, но возможно следующее (сейчас)
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
Ответ 5
VB.NET не поддерживает неявное выполнение.
Я также столкнулся с этой проблемой и имел массу проблем.
Когда вы работаете с сгенерированными классами (сущностями и т.д.), где вы должны явно объявлять Implements IFoo
, это делает невозможным вообще.
Поэтому Я отправил соединение с Microsoft, и я надеюсь, вы проголосуете и в следующей версии VB они улучшат компилятор, чтобы быть более умными.
Ответ 6
Я не могу комментировать ответ MA Hanin из-за моей репутации, но я бы порекомендовал одну небольшую настройку, чтобы избежать предупреждений компилятора о скрытии базовых методов, предполагая, что вы не хотите или не можете переопределить переопределение свойства в базовый класс.
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
Ответ 7
Это странная проблема, и она явно показывает разницу между компиляторами С# и VB.NET. Я бы предположил, что вы реализуете интерфейс в абстрактном базовом классе, так как это сделает компилятор VB.NET счастливым, и во время выполнения ваш дочерний класс будет по-прежнему иметь метаданные, указывающие, что он действительно реализует IFoo
.
Есть ли конкретная причина, согласно которой дочерний класс должен объявить, что он реализует интерфейс?