为了避免陷入我的特定程序的杂草,让我创建一个简化的案例。
我有一个泛型类,可以处理各种对象。每个对象都必须实现某个接口。
我想说的是:
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,我不能解决这个问题?
答案 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)