.NET: Interface Problem VB.net Getter Only Interface
Why does an interface override a class definition and violate class encapsulation? I have included two samples below, one in C# and one in VB.net?
VB.net
Module Module1
Sub Main()
Dim testInterface As ITest = New TestMe
Console.WriteLine(testInterface.Testable) ''// Prints False
testInterface.Testable = True ''// Access to Private!!!
Console.WriteLine(testInterface.Testable) ''// Prints True
Dim testClass As TestMe = New TestMe
Console.WriteLine(testClass.Testable) ''// Prints False
''//testClass.Testable = True ''// Compile Error
Console.WriteLine(testClass.Testable) ''// Prints False
End Sub
End Module
Public Class TestMe : Implements ITest
Private m_testable As Boolean = False
Public Property Testable As Boolean Implements ITest.Testable
Get
Return m_testable
End Get
Private Set(ByVal value As Boolean)
m_testable = value
End Set
End Property
End Class
Interface ITest
Property Testable As Boolean
End Interface
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace InterfaceCSTest
{
class Program
{
static void Main(string[] args)
{
ITest testInterface = new TestMe();
Console.WriteLine(testInterface.Testable);
testInterface.Testable = true;
Console.WriteLine(testInterface.Testable);
TestMe testClass = new TestMe();
Console.WriteLine(testClass.Testable);
//testClass.Testable = true;
Console.WriteLine(testClass.Testable);
}
}
class TestMe : ITest
{
private bool m_testable = false;
public bool Testable
{
get
{
return m_testable;
}
private set
{
m_testable = value;
}
}
}
interface ITest
{
bool Testable { get; set; }
}
}
More Specifically
How do I implement a interface in VB.net that will allow for a private setter. For example in C# I can declare:
class TestMe : ITest
{
private bool m_testable = false;
public bool Testable
{
get
{
return m_testable;
}
private set //No Compile Error here!
{
m_testable = value;
}
}
}
interface ITest
{
bool Testable { get; }
}
However, if I declar开发者_Python百科e an interface property as readonly in VB.net I cannot create a setter. If I create a VB.net interface as just a plain old property then interface declarations will violate my encapsulation.
Public Class TestMe : Implements ITest
Private m_testable As Boolean = False
Public ReadOnly Property Testable As Boolean Implements ITest.Testable
Get
Return m_testable
End Get
Private Set(ByVal value As Boolean) ''//Compile Error
m_testable = value
End Set
End Property
End Class
Interface ITest
ReadOnly Property Testable As Boolean
End Interface
So my question is, how do I define a getter only Interface in VB.net with proper encapsulation?
I figured the first example would have been the best method. However, it appears as if interface definitions overrule class definitions. So I tried to create a getter only (Readonly) property like in C# but it does not work for VB.net. Maybe this is just a limitation of the language?
Update
As per Hans Passant's comment I have submitted a feature request found : https://connect.microsoft.com/VisualStudio/feedback/details/635591/create-a-readonly-interface-that-allows-private-setters-c-to-vb-net-conversion
Please vote for it if you would like the same compatibility feature as well!
Here's how I'd do it in VB.NET:
Public Interface ITest
ReadOnly Property Testable As Boolean
End Interface
Public Class Test
Implements ITest
' Note: Here I am NOT implementing the interface. '
Private _testable As Boolean
Public Property Testable() As Boolean
Get
Return _testable
End Get
Private Set(ByVal value As Boolean)
_testable = value
End Set
End Property
' This is where I define a read-only property to satisfy the interface '
' (from the perspective of the VB compiler). '
' Notice this is a lot like explicit interface implementation in C#. '
Private ReadOnly Property TestableExplicit() As Boolean Implements ITest.Testable
Get
Return Testable
End Get
End Property
End Class
When an interface calls for a read-only property, your implementation should omit the setter. Properties declared 'Read-Only' cannot have a 'Set'.
Dan answered your second question, let me answer your first one:
Why does an interface override a class definition and violate class encapsulation?
This is not specific to properties. Consider the following (simpler) example, which shows the same behavior as your example:
Interface I
Sub DoSomething()
End Interface
What does this mean? It means that if you have an object i
of type I
, you can always call i.DoSomething()
publicly.
Public Class C
Implements I
Private Sub DoSomething() Implements I.DoSomething
...
End Sub
End Class
By using Implements I.DoSomething
, you specify that if an object of class C
is accessed through interface I
, calling I.DoSomething
will execute your private method C.DoSomething
(which happens to share the same name, but that's just a coincidence). This is not a violation of encapsulation: By using Implements ...
, you specify that you want this method to be accessible via this (public) interface method. So, basically, you can think of the Implements
keyword as providing a second means of access to this method (or property, in your example), which is independent of the access modifiers of the "main" means of access.
Thus, DirectCast(myC, I).DoSomething()
will work (since it accesses the interface method, which happens to "call" your private method), but myC.DoSomething()
will not compile when used outside of C
.
The same thing happens in your example: Specifying Property Testable As Boolean
in your interface guarantees that obj.Testable = ...
can be called (publicly) on every obj
of type ITest
.
精彩评论