After restricting Setter scope and then applying an interface, scope is disregarded!
Question
If I set a Friend-level scope on a setter, like this...
Public Class MyClass
Public Property IsDirty() As Boolean
Get
Return _isDirty
End Get
Friend Set(ByVal trueFalse As Boolean)
_isDirty = trueFalse
End Set
End Property
End Class
...And then call it from another project, it works correctly. I can't do something like MyClass.IsDirty = True.
Great! That's exactly what I want.
But now if I define an interface, and I will indeed have to do that:
Public Interface IMyClass
Property IsDirty() As Boolean
End Interface
I can do something like:
Dim MyInstance as IMyClass= GetSomeInstanceOfMyClass()
MyInstance.IsDirty=True
...And, bizarrely, it runs! No exceptions are thrown, and the inner variable is set to True. It ignores the Friend scope completely!
That's hideous. What am I missing??
Note: I need this because I'm designing an API, and I want the inner API to be able to set IsDirty, but end-developers shouldn't be able to get into that. Currently I am wrapping the whole class in a facade to get this functionality, but the facade should be unecessary.
Solution
Interface methods always have public accessibility. You can't fix that by explicit interface implementation, that will only hide the class method. Simply casting the object to the interface type gives unfettered access again.
EDIT: actually, the problem is easy to solve. Just declare the property ReadOnly in the interface declaration :)
For example:
Public Interface IMyClass
ReadOnly Property IsDirty() As Boolean
End Interface
Public Class Test
Implements IMyClass
Private mIsDirty As Boolean
Private ReadOnly Property IsDirtyImpl() As Boolean Implements IMyClass.IsDirty
Get
Return mIsDirty
End Get
End Property
Public Property IsDirty() As Boolean
Get
Return mIsDirty
End Get
Friend Set(ByVal value As Boolean)
mIsDirty = value
End Set
End Property
End Class
OTHER TIPS
What you are missing is the concept of inplicit and explicit interface implementation. See the answer to this question for more details.
And if you think it's hideous with a Friend setter, try setting it to Private and watch it still be accessible via the interface!