Необязательное свойство только для чтения в интерфейсе VB.Net - PullRequest
3 голосов
/ 26 августа 2009

Я пытаюсь разработать простой интерфейс, позволяющий генерировать быстрые списки из классов. По сути, интерфейс должен возвращать идентификатор и имя. Однако некоторые классы имеют вычисляемое свойство name, которое доступно только для чтения, другие просто используют свойство name для чтения / записи. В принципе, все, что меня волнует, - это то, что у него есть геттер, не имеет значения, есть ли у свойства сеттер. Как я могу написать этот интерфейс для обработки или без выдачи ошибок компиляции?

Я прочитал этот вопрос и не очень следил за ним, может быть, я просто дремучий. Если да, пожалуйста, покажи мне ошибку моих способов:)

1 Ответ

5 голосов
/ 26 августа 2009

Похоже, ответ на другой вопрос будет работать: вот пример:

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
...