因此VB界面不具备共享功能。是否有创建虚拟对象的替代方法?

时间:2015-05-29 15:33:48

标签: vb.net generics

为了避免陷入我的特定程序的杂草,让我创建一个简化的案例。

我有一个泛型类,可以处理各种对象。每个对象都必须实现某个接口。

我想说的是:

Public Interface GenThing
    Shared Function thing_name() As String ' This doesn't work! Can't be shared!
    Sub FillOne(row As DataRow)
End Interface

public class Thing1
  implements GenThing
    public shared function thing_name() as string implements GenThing.thing_name
        return "thing number one"
    end function

    public sub FillOne(row as DataRow) implements GenThing.MakeOne
        ... bunch of work ...
    end sub
end class

public class ThingUtil(of T as {GenThing,New})
    public function GetList(id as integer) as List(of T)
      dim name=T.thing_name() ' This doesn't work!
      dim ds as DataSet=GetData(name,id) ' bunch of work here that's the whole point of the class but not relevant to the question
      dim my_list = new List(of T)
      for each row as DataRow in ds.tables(0).rows
          dim my_t = new T()
          my_t.FillOne(row)
          my_list.add(my_t)
      next
      return my_list
    end function
end class

你有我的问题吗?我需要每个实现接口的类都有一个返回" name"的函数。用于获取创建对象实例所需的数据。但是我需要在创建实例之前知道这个名称,因为我需要它才能创建实例。但是VB并不允许接口具有共享功能,所以我想写的东西不起作用。

所以我所做的就是:

我使thing_name不共享。

然后,而不是简单的" dim name = T.thing_name()",我写

dim dummy = new T()
dim name = dummy.thing_name()

好的,它有效,但看起来真的很难看。我创建了一个对象的实例,其中包含所有开销,只是为了得到一段不变的文本。

有更好的方法吗?或者我从无到有做大事?

更新

我看到有两个人投票结束这个问题,理由是它和#34;为什么我们不能在界面中共享功能?"

我不是在问为什么我不能分享。我说,GIVEN,我不能解决这个问题?

2 个答案:

答案 0 :(得分:2)

没有非常简单的方法来解决这个问题,没有。

但是,根据thing_name的作用,您可能会以不同的方式处理事情。如果每个实现只返回一个常量值,那么它实际上是关于类的元数据 - 并且可以在属性中进行描述,这可以在执行时获取。 (请参阅Type.GetCustomAttributes。)遗憾的是,您无法强制执行使用该属性修饰的接口的所有类型 - 但您可以编写单元测试来轻松检查这一点。

如果thing_name需要在执行时真正起作用,那就更难了。你可能会寻找一个众所周知的共享方法名称,并通过反射执行它(并再次进行单元测试以检查它是否正确实现)。

答案 1 :(得分:0)

我意识到这是几年前的事,但遇到类似的问题,我想提供一个不同的解决方案。将委托作为参数传递给ThingUtil构造函数。您可以避免在接口中放置共享方法,构造函数将强制您在编译时包含该参数。

如果需要,您可以添加更多代理,或者在这种情况下更简单,只需将name作为字符串而不是get_name作为代理传递。

在界面中定义委托:

Public Interface GenThing
  Delegate Function ThingNameDelegate() As String
  Sub FillOne(row As DataRow)
End Interface

Public Class Thing1
  Implements GenThing

  Public Shared Function thing_name() As String 'name this whatever you want
    Return "thing number one"
  End Function

  Public Sub FillOne(row As DataRow) Implements GenThing.FillOne
      'do stuff
  End Sub
End Class

在ThingUtil中,添加一个成员来存储委托,一个要接受的构造函数参数,并使用.Invoke()调用它:

Public Class ThingUtil(Of T As {GenThing, New})
        Private m_thing_name As GenThing.ThingNameDelegate

        Public Sub New(thing_name As GenThing.ThingNameDelegate)
            m_thing_name = thing_name
        End Sub
        Public Function GetList(id As Integer) As List(Of T)
            Dim name = m_thing_name.Invoke()
            Dim ds As DataSet = GetData(name, id) ' bunch of work here that's the whole point of the class but not relevant to the question
            Dim my_list = New List(Of T)
            For Each row As DataRow In ds.Tables(0).Rows
                Dim my_t = New T()
                my_t.FillOne(row)
                my_list.Add(my_t)
            Next
            Return my_list
        End Function
End Class

最后,像这样使用它:

Dim tu as new ThingUtil(Of Thing1)(AddressOf Thing1.get_name)
tu.GetList(1)