【问题标题】:VB.NET class inherits a base class and implements an interface issue (works in C#)VB.NET 类继承基类并实现接口问题(在 C# 中工作)
【发布时间】:2011-02-06 03:56:56
【问题描述】:

我正在尝试在 VB.NET 中创建一个类,它继承了一个基本抽象类并实现了一个接口。该接口声明了一个名为 Description 的字符串属性。基类包含一个名为 Description 的字符串属性。主类继承基类并实现接口。基类中存在的 Description 属性满足了接口要求。这在 C# 中运行良好,但在 VB.NET 中会导致问题。

首先,这是一个有效的 C# 代码示例:

public interface IFoo
{
    string Description { get; set; }
}

public abstract class FooBase
{
    public string Description { get; set; }
}

public class MyFoo : FooBase, IFoo
{
}

现在这是给出编译器错误的 VB.NET 版本:

Public Interface IFoo
    Property Description() As String
End Interface

Public MustInherit Class FooBase
    Private _Description As String
    Public Property Description() As String
        Get
            Return _Description
        End Get
        Set(ByVal value As String)
            _Description = value
        End Set
    End Property
End Class

Public Class MyFoo
    Inherits FooBase
    Implements IFoo
End Class

如果我让基类(FooBase)实现接口并将Implements IFoo.Description添加到属性中,一切都很好,但我不希望基类实现接口。

编译错误是:

类“MyFoo”必须为接口“IFoo”实现“Property Description() As String”。实现属性必须具有匹配的“ReadOnly”或“WriteOnly”说明符。

VB.NET 不能处理这个问题,还是我需要在某个地方更改我的语法才能让它工作?

【问题讨论】:

  • C# 代码无法编译,因为它没有实现抽象类的描述。你确定你真的想要一个接口和抽象基吗?
  • @gbogumil - C# 版本确实 编译 - 接口实现在基类中。
  • 下面的答案回答了你的问题——我个人认为这是尝试在 VB.net 中编写干净代码时最烦人的事情之一......
  • @Chris - 但是 FooBase 不会实现这个接口,MyFoo 会,并且它确实通过继承具有适当的属性。我没有看到鸭子在这里打字。
  • @300 波特,我希望我们现在和@Paddy 在酒吧里,这将是一个有趣的醉酒争论!这是我的最后一次,这只是我的看法。如果你有一个“Fruit”的基类,它的属性是“Name”,你用“Apple”子类化它并实现“INameable.Name”,你说的是“Apple继承自Fruit,它已经有一个名为Name的属性,我不'真的不知道它做了什么,但只是用它来履行合同“。我个人认为你应该明确地这样做,即使它只是对“base.Name”的调用。

标签: c# vb.net


【解决方案1】:

无论哪种方式,您都必须指定 IFoo 接口的实现细节。

这个简单的选项怎么样?

Public Class MyFoo
    Inherits FooBase
    Implements IFoo
    Overloads Property Description() As String Implements IFoo.Description
        Get
            Return MyBase.Description
        End Get
        Set(ByVal value As String)
            MyBase.Description = value
        End Set
    End Property
End Class

【讨论】:

  • 自从写了这个答案已经有一段时间了,但只是想说这是我实施的解决方案,但 NDepend 对这句话“不要隐藏基类方法”抛出了一个严重错误。烦人
【解决方案2】:

您需要在基类中将您的属性标记为OverridableMustOverride,然后您可以在子类中覆盖它:

Public MustInherit Class FooBase
    Private _Description As String
    Public Overridable Property Description() As String
        Get
            Return _Description
        End Get
        Set(ByVal value As String)
            _Description = value
        End Set
    End Property
End Class

Public Class MyFoo
    Inherits FooBase
    Implements IFoo
    Public Overrides Property Description() As String Implements IFoo.Description
        Get
            Return MyBase.Description
        End Get
        Set(ByVal value As String)
            MyBase.Description = value
        End Set
    End Property
End Class

编辑 这是对@M.A. 的回应。韩宁发文。我们的两种解决方案都有效,但了解每种解决方案的影响很重要。想象一下下面的代码:

Dim X As FooBase = New MyFoo()
Trace.WriteLine(X.Description)

X.Description 的结果是什么?使用 Overridable 您将获得对子类的调用,而使用 Overload 方法您将获得对基类的调用。没有对错,重要的是要了解声明的后果。使用 Overload 方法,您必须向上转换才能获得孩子的实现:

Trace.WriteLine(DirectCast(X, MyFoo).Description)

如果您只是从子类调用 MyBase.Description,则问题没有实际意义,但如果您更改了子类的定义,那么您只需要确保您了解发生了什么。

【讨论】:

  • 先生。哈斯,很高兴在 VB.NET 主题中再次遇到您 :-) 我也只是在考虑这个解决方案,但决定放弃它,以支持“按原样”保留基类。然而,这是一个完全有效的解决方案。 +1!
  • 我倾向于将此标记为答案,尽管我希望情况并非如此。知道我正在覆盖一个基本属性只是为了调用我正在覆盖的基本属性,这让我感到恶心。我知道这必须是 VB.NET 的一个约束(我不会称之为限制),因为即使基类履行合同,实现类也必须直接在类中定义合同属性。也许 VB.NET 最终会隐式实现一个成员,而不需要 'Implements' 关键字。
  • 如果您不想覆盖,请使用重载(请参阅我的帖子)。 VB.NET的接口实现机制在某些方面相当灵活,而在其他方面则不够灵活。实现属性不必具有相同的访问级别、方法名称或参数名称。由于这种灵活的机制,隐式接口实现不得不被忽略。
  • 我的问题不在于是使用 Overloads 还是 Overrides。我的问题是必须将属性添加到 MyFoo 当它已经在基类中时。但似乎重新声明属性以满足接口契约是 VB.NET 的约束。
  • 我已经用我的帖子和@M.A. 之间的差异更新了我的帖子。韩宁的帖子。没有对错,你只需要了解每个实施的后果。
【解决方案3】:

这是一个奇怪的问题,它清楚地显示了 C# 和 VB.NET 编译器之间的差异。我建议您在抽象基类上实现接口,因为这将使 VB.NET 编译器满意,并且在执行时您的子类仍然有元数据表明它确实实现了IFoo

子类必须是声明它实现接口的特定原因吗?

【讨论】:

  • 好问题。为什么不把“Implements IFoo”放在 FooBase 中?
【解决方案4】:

VB 要求实现属性声明实现。这是因为我实际上认为 VB 的一个很好的特性是我在 C# 中有时会错过的——你可以重命名实现接口成员的成员。

因此,在FooBase 中不实现IFoo.Description 的唯一方法是声明Description Overridable,然后将MyFoo 定义为:

Public Class MyFoo
    Inherits FooBase
    Implements IFoo

    Public Overrides Property Description() As String Implements IFoo.Description
        Get
            Return MyBase.Description
        End Get
        Set(ByVal value As String)
            MyBase.Description = value
        End Set
    End Property
End Class

【讨论】:

  • 我相信您也可以在 C# 中显式地实现接口成员,这样您就可以重命名实现类中的成员。
  • @MikeCole C# 中显式实现的接口成员将与接口上的名称相同。您始终可以在调用显式实现的具体类上添加其他成员,将this 转换为接口类型,但这在使用接口时不会为您带来任何好处。
  • 哦,真的吗?我认为明确声明它将允许您使用不同的名称。我想我从未尝试过。
【解决方案5】:

VB.NET 不支持隐式实现。 我也遇到了这个问题,遇到了很多麻烦。

当您使用必须显式声明Implements IFoo 的生成类(实体等)时,这根本不可能。

因此I submitted a connection to Microsoft,我希望你能投票,下一个版本的 VB 他们会改进编译器,使其更聪明。

【讨论】:

  • 这应该是公认的答案。当前接受的答案不仅仅是“语法更改”,而是针对 VB.NET 不支持隐式实现的限制的解决方法。
【解决方案6】:

对不起,如果我迟到了,如果此功能仅在 .NET 4 中引入,也很抱歉,但以下是可能的(现在)

Public Interface IFoo
    Property Description() As String
End Interface

Public MustInherit Class FooBase
    Implements IFoo

    Public MustOverride Property Description As String Implements IFoo.Description
End Class

Public Class MyFoo
    Inherits FooBase

    Private _description As String

    Public Overrides Property Description As String
        Get
            Return _description
        End Get
        Set(value As String)
            _description = value
        End Set
    End Property
End Class

【讨论】:

    【解决方案7】:

    由于我的代表,我无法评论 MA Hanin 的回答,但我建议您进行一些小调整,以避免编译器警告有关隐藏基本方法的警告,假设您不想或无法覆盖覆盖基类。

    Public Class MyFoo
        Inherits FooBase
        Implements IFoo
        Private Property IFoo_Description() As String Implements IFoo.Description
            Get
                Return Me.Description
            End Get
            Set(ByVal value As String)
                Me.Description = value
            End Set
        End Property
    End Class
    

    【讨论】:

      猜你喜欢
      • 2011-01-01
      • 2012-07-15
      • 2019-03-23
      • 1970-01-01
      • 2017-10-23
      • 1970-01-01
      • 2012-05-14
      • 1970-01-01
      • 2011-09-12
      相关资源
      最近更新 更多