Похоже, ответ на другой вопрос будет работать: вот пример:
Public Interface IReadOnly
ReadOnly Property Name() As String
End Interface
Public Interface IReadWrite
Inherits IReadOnly
Overloads Property Name() As String
End Interface
Public Class ReadOnlyClass
Implements IReadOnly
Private _Name
Public ReadOnly Property Name() As String Implements IReadOnly.Name
Get
Return _Name
End Get
End Property
End Class
Public Class ReadWriteClass
Implements IReadWrite
Private ReadOnly Property ReadOnly_Name() As String Implements IReadOnly.Name
Get
Return Name
End Get
End Property
Private _Name As String
Public Overloads Property Name() As String Implements IReadWrite.Name
Get
Return _Name
End Get
Set(ByVal value As String)
_Name = value
End Set
End Property
End Class
Приведенный выше подход фактически приведет к тому, что классы, реализующие IReadWrite, также реализуют IReadOnly - так что вам действительно нужно будет уменьшить значение до IReadWrite, чтобы установить свойство.
Другой подход, который позволяет избежать этой проблемы, но требует немного больше логики в реализующих классах и их вызывающих программах, что-то вроде:
Public Interface ISometimesWritable
Property Name() As String
ReadOnly Property AllowNameEdit() As Boolean
End Interface
Public Class ReadOnlyClass
Implements ISometimesWritable
Public ReadOnly Property AllowNameEdit() As Boolean Implements ISometimesWritable.AllowNameEdit
Get
Return False
End Get
End Property
Private _Name As String
Public Property Name() As String Implements ISometimesWritable.Name
Get
Return _Name
End Get
Set(ByVal value As String)
Throw New NotSupportedException("Name cannot be set when AllowNameEdit is False")
End Set
End Property
End Class
Public Class ReadWriteClass
Implements ISometimesWritable
Public ReadOnly Property AllowNameEdit() As Boolean Implements ISometimesWritable.AllowNameEdit
Get
Return True
End Get
End Property
Private _Name As String
Public Property Name() As String Implements ISometimesWritable.Name
Get
Return _Name
End Get
Set(ByVal value As String)
_Name = value
End Set
End Property
End Class
Обновление: Для ответа на вопрос о даункастинге; «downcasting» - это термин, используемый для описания преобразования объекта из суперкласса, интерфейса или абстрактного базового класса Type
в более конкретный Type
.
Например, первый пример выше определяет два интерфейса: IReadOnly
и IReadWrite
. Вы заметите, что IReadWrite
реализует IReadOnly
, что означает, что вы можете совершать как IReadWrite
, так и IReadOnly
вызовы объектов, которые реализуют IReadWrite
.
Поскольку IReadWrite
реализует IReadOnly
, IReadWrite
называется «подклассом» IReadOnly
(хотя «подкласс» более точно используется для описания класса, который наследует базовый класс, а не реализует интерфейс - для простоты они очень похожи друг на друга). Если IReadWrite
является подклассом IReadOnly
, тогда обратное верно: IReadOnly
является суперклассом из IReadWrite
.
Например, я могу описать экземпляр ReadWriteClass
как реализацию любого интерфейса:
Public Sub SomeMethod()
dim readOnlyInstance as IReadOnly = new ReadWriteClass()
Console.WriteLine(readOnlyInstance.Name)
' The following line won't compile, since we're communicating with ReadWriteClass as an instance of IReadOnly
'readOnlyInstance.Name = "Santa Clause"
' Here we downcast the variable to reference it by it's other interface, IReadWrite
dim readWriteInstance = DirectCast(readOnlyInstance, IReadWrite)
' Now we can both Get and Set the value of Name
readWriteInstance.Name = "John Doe"
Console.WriteLine(readWriteInstance.Name)
' Note that in the above example we created *one* instance of ReadWriteClass
' and have provided two variables / references to the same underlying object.
Console.WriteLine(readOnlyInstance.Name) ' <-- note that this should return "John Doe"
End Sub