5
votes

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 declare 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!

3
You can't, it is not permitted syntax. Post a feature request at connect.microsoft.com, the team is receptive to any requests that make both languages feature comparable. For now, you'll have to use a private method to set the backing field.Hans Passant
@Hans Passant. Thank you. Feature Request can be found here: connect.microsoft.com/VisualStudio/feedback/details/635591/…user295190
You need to removed the ReadOnly. Period.AMissico
@AMissico: Why? Now I have just given access to my private variable through Interface instances. I think Hans Passant's answer is more appropriate.user295190
I upvoted the feature request, good ask. One downvote, I didn't realize that that connect was stackoverflowian. First time I've seen that.Hans Passant

3 Answers

4
votes

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
1
votes

When an interface calls for a read-only property, your implementation should omit the setter. Properties declared 'Read-Only' cannot have a 'Set'.

0
votes

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.