【问题标题】:Deal with Null object references through Interfaces通过 Interfaces 处理 Null 对象引用
【发布时间】:2019-07-30 23:05:36
【问题描述】:

我有一个对象Foo,但我并不拥有它(第三方程序集),我想通过接口IFoo

在通过接口传递所有内容之前,我有一个Function TryGet(Name As String) as Foo。当找不到名称时,此函数将返回 Nothing

现在将所有内容重构为接口,我有Function TryGet(Name As String) as IFoo

IFoo的实现是:

Public Class SuperFoo
    Implements IFoo

    Private ThisFoo As Foo

    Private Sub New()
    End Sub

    Public Sub New(MyFoo As Foo)
        Me.ThisFoo = MyFoo
    End Sub

    Public Property Value As String Implements IFoo.Value
        Get
            Return Me.ThisFoo.Value
        End Get
        Set(value As String)
            Me.ThisFoo.Value = value
        End Set
    End Property

End Class

Class AnotherClass

    Function TryGet(Name as String) as IFoo
        Dim MyFoo as Foo = InitialTryGetFunction(Name)
        Return New SuperFoo(MyFoo)
    End Function

End Class

为了保持我的原始代码逻辑,我希望能够在InitialTryGetFunction 返回空引用时将对SuperFoo 对象的引用设为空。

显然我可以在If Return New SuperFoo(MyFoo) 语句中添加一些代码,但我想知道这是否可以通过SuperFoo 构造函数完成?

另外,我是否正确地切换到接口(主要用于单元测试)?

【问题讨论】:

  • “我希望能够将 SuperFoo 对象设为 null”。只是为了记录,这没有任何意义。您不能使对象为空。根据定义,Null 不是对象。引用在没有引用对象时为 null,因此您希望返回不引用任何对象的 SuperFoo 引用。
  • 当 InitialTryGetFunction 返回空引用时,我希望能够将对 SuperFooobject 的引用设为空。

标签: vb.net interface


【解决方案1】:

您可以使用SuperFoo 中的扩展运算符来完成此操作,该运算符将Foo 转换为SuperFoo。由于运算符是Shared,如果给定的FooNothing,则可以返回Nothing,否则返回一个新的SuperFoo

Public Shared Widening Operator CType(ByVal x As Foo) As SuperFoo
    Return If(x Is Nothing, Nothing, New SuperFoo(x))
End Operator

VB.Net 解决的很好,我想你甚至可以像这样直接退货(未经测试,无保修):

    Function TryGet(Name as String) as IFoo
        Return InitialTryGetFunction(Name) 'Converts into SuperFoo which is cast into IFoo
    End Function

(如果不起作用,请使用)

    Function TryGet(Name as String) as IFoo
        Dim myResult As SuperFoo = InitialTryGetFunction(Name)
        Return myResult
    End Function

【讨论】:

  • 这听起来很有希望,而且似乎在做我想做的事:从 SuperFoo 类内部处理空引用。会试一试,然后回复你。非常感谢!
  • 判决:在我的情况下它不起作用,因为 Foo 实际上是一个接口(通过 COM 互操作公开),所以转换运算符不可用:(。还有其他想法吗?
  • 我确实通过创建一个常规的共享函数来解决这个问题,它与 CType 完全相同,但名称不同,需要显式调用。不那么漂亮,但它可以完成工作!
【解决方案2】:

根据 Christoph 的回答,我遇到了一个后续问题,即 Foo 实际上是一个接口本身(通过 COM 互操作公开)。

对于面临同样问题的任何人,这是我的处理方法:

Public Class SuperFoo
    Implements IFoo

    Private ThisFoo As Foo

    Private Sub New()
    End Sub

    Public Sub New(MyFoo As Foo)
        Me.ThisFoo = MyFoo
    End Sub

    Public Shared Function GetNew(obj as Foo) As SuperFoo
        Return If(obj Is Nothing, Nothing, New SuperFoo(obj))
    End Function

    Public Property Value As String Implements IFoo.Value
        Get
            Return Me.ThisFoo.Value
        End Get
        Set(value As String)
            Me.ThisFoo.Value = value
        End Set
    End Property

End Class

Class AnotherClass

    Function TryGet(Name as String) as IFoo
        Dim MyFoo as Foo = InitialTryGetFunction(Name)
        Return SuperFoo.GetNew(MyFoo)
    End Function

End Class

我给 Christoph 提供了公认的答案,因为他提供了一般情况的答案。

【讨论】:

  • 它应该按照我的建议工作(至少下面的替代版本),因为 SuperFoo 是一个托管类而不是 COM 接口。在那里你实现了扩展运算符。
  • .net 不会让你从一个界面扩展到其他东西。您可以从一个对象扩展为一个接口,但反向不编译。最后我所做的与工厂非常相似,尽管工厂在它实例化的类中..
  • 我找到了根本原因:docs.microsoft.com/en-us/dotnet/visual-basic/misc/bc33029。在任何情况下,再次感谢您为我指明了正确的方向,我很高兴使用工厂而不是操作员;发现它更安全。
猜你喜欢
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 2016-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-19
  • 1970-01-01
相关资源
最近更新 更多