【问题标题】:.NET: Interface Problem VB.net Getter Only Interface.NET:接口问题 VB.net Getter Only Interface
【发布时间】:2011-01-11 20:35:48
【问题描述】:

为什么一个interface会覆盖一个class定义并违反类封装?我在下面包含了两个示例,一个在 C# 中,一个在 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; }
    }
}

更具体

如何在 VB.net 中实现一个接口,以允许 private setter。例如在 C# 中我可以声明:

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; }
}

但是,如果我在 VB.net 中将 interface 属性声明为 readonly,我将无法创建 setter。如果我将 VB.net interface 创建为一个普通的旧 property,那么接口声明将违反我的 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

所以我的问题是,如何在 VB.net 中定义一个 getter only Interface 并进行适当的封装?

我认为第一个示例可能是最好的方法。但是,似乎接口定义凌驾于类定义之上。所以我尝试创建一个 getter only (Readonly) property,就像在 C# 中一样,但它不适用于 VB.net。也许这只是语言的限制?

更新

根据 Hans Passant 的评论,我已提交功能请求,发现:https://connect.microsoft.com/VisualStudio/feedback/details/635591/create-a-readonly-interface-that-allows-private-setters-c-to-vb-net-conversion

如果您也想要相同的兼容性功能,请投票!

【问题讨论】:

  • 你不能,这是不允许的语法。在 connect.microsoft.com 上发布功能请求,团队将接受任何使两种语言功能具有可比性的请求。现在,您必须使用私有方法来设置支持字段。
  • @Hans Passant。谢谢你。功能请求可以在这里找到:connect.microsoft.com/VisualStudio/feedback/details/635591/…
  • 您需要删除 ReadOnly。期间。
  • @AMissico:为什么?现在我刚刚通过接口实例访问了我的私有变量。我觉得 Hans Passant 的回答比较合适。
  • 我赞成功能请求,问得好。一票否决,我没有意识到那个连接是stackoverflowian。我第一次看到。

标签: c# .net vb.net


【解决方案1】:

这是我在 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

【讨论】:

  • 谢谢。我一直想知道为什么 VB.net 必须明确说明它的实现。这是有道理的。
  • @user295190 在我看来,与其说是“不得不”,不如说是“必须”。在接口实现的命名和可见性方面,VB 比 C# 更灵活。
【解决方案2】:

当接口调用只读属性时,您的实现应该省略 setter。声明为“只读”的属性不能有“设置”。

【讨论】:

  • 我知道 (Readonly Property Testable as Boolean) != ( bool Testable { get; } )。我想知道如何在 VB.net 中实现类似的功能。
  • 还有一点需要注意 - 与其说是语言限制,不如说是句法差异。 ReadOnly 关键字是 VB.NET 对私有 setter 的回答。
【解决方案3】:

丹回答了你的第二个问题,我来回答你的第一个问题:

为什么接口会覆盖类定义并违反类封装?

这并不特定于属性。考虑以下(更简单的)示例,它显示的行为与您的示例相同:

Interface I
    Sub DoSomething()
End Interface

这是什么意思?这意味着如果你有一个i 类型为I 的对象,你可以随时公开调用i.DoSomething()。

Public Class C
    Implements I
    Private Sub DoSomething() Implements I.DoSomething
        ...
    End Sub
End Class

通过使用Implements I.DoSomething,您指定如果通过接口I访问类C的对象,调用I.DoSomething将执行您的私有方法C.DoSomething(发生这种情况共享相同的名字,但这只是一个巧合)。这不违反封装:通过使用Implements ...,您指定您希望通过此(公共)接口方法访问此方法。因此,基本上,您可以将 Implements 关键字视为提供对该方法(或您的示例中的属性)的第二种访问方式,它独立于“主要”访问方式的访问修饰符。

因此,DirectCast(myC, I).DoSomething() 将起作用(因为它访问接口方法,而这恰好“调用”了您的私有方法),但在 C 之外使用时,myC.DoSomething() 将无法编译。

在您的示例中也发生了同样的事情:在您的界面中指定 Property Testable As Boolean 可以保证在每个 ITest 类型的 obj 上都可以(公开)调用 obj.Testable = ...。

【讨论】:

  • 感谢您的澄清。
猜你喜欢
  • 2010-10-20
  • 1970-01-01
  • 2011-10-12
  • 2012-12-14
  • 1970-01-01
  • 1970-01-01
  • 2011-06-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多