【问题标题】:vb.net: calling constructor when using genericsvb.net:使用泛型时调用构造函数
【发布时间】:2021-10-08 05:35:58
【问题描述】:

我不确定这是否可能。

我有许多实现接口 IBar 的不同类,并且有接受几个值的构造函数。与其创建一堆几乎相同的方法,是否可以有一个通用方法来创建适当的构造函数?

private function GetFoo(Of T)(byval p1, byval p2) as List(Of IBar)
  dim list as new List(Of IBar)

  dim foo as T

  ' a loop here for different values of x
     foo = new T(x,p1) 
     list.Add(foo)
  ' end of loop
  return list
end function

我明白了:

'New' cannot be used on a type parameter that does not have a 'New' constraint. 

【问题讨论】:

    标签: vb.net generics


    【解决方案1】:

    不幸的是,.NET 泛型仅允许您将泛型类型约束为具有无参数构造函数,然后您可以使用New T() 调用它...您不能指定一组特定的参数。

    如果你不介意让你的类型可变,你可以创建一个接口,其中包含一个带有相关参数的方法,让你的所有类型都实现这个接口,然后约束要实现的类型该方法并具有无参数构造函数,但并不理想。

    另一种选择是传入一个适当的Func,它接受xp1,每次都返回一个新的T。这在 C# 中肯定很容易使用 - 在 VB IIRC 中不是相当那么容易,但值得考虑。

    【讨论】:

    • Func 现在在 VB.net 中是可以的。它仍然比 C# 更冗长。
    • @toddmo:如果您将泛型类型约束为具有无参数构造函数,它将起作用。如果你没有那个约束,它就行不通。
    • @JonSkeet,如果你写了Sub Foo(Of T As {MyClass, New}) 来表明你的意思,我就不会感到困惑了。你说了些什么,但没有说明。谢谢。
    • 关于您提到的第一个选项:您是否建议通过无参数构造函数创建对象,然后运行 ​​function 这将完成应该在原始参数中完成的工作-完整的构造函数?换句话说,类似于GetFoo(of T As IBar)(p1, p2): ... : Dim Bar as New T : Bar.FinishConstruction(x, p1)(其中FinishConstructionIBar 的一部分,由Bar 实现)?
    【解决方案2】:

    扩展 Jon Skeet 的答案,这是使用 Func 参数的可能解决方案:

    Private Function GetFoo(Of T As IBar)(ByVal p1 As Object, ByVal p2 As Object, ctor As Func(Of Integer, Object, T)) As List(Of IBar)
        Dim list As New List(Of IBar)
        Dim foo As T
        For x = 1 To 10
            foo = ctor(x, p1)
            list.Add(foo)
        Next
        Return list
    End Function
    

    用法类似于

        GetFoo(1, 2, Function(i, o) New BarImpl(i, o))
    

    【讨论】:

    • 当我尝试将 Function BarImpl(i,o) 创建为 FOO { return new FOO(i,o) } 时,我在调用 GetFoo 时收到错误消息,提示未定义 BarImpl。
    • BarImpl 是实现IBar 的类,而不是Function
    • 使用工厂方法是一个绝妙的主意。一旦它到位,它可能也比构造函数更可取,因为你可以像在构造方法中注入状态一样思考,而在真正的构造函数中是无法做到的。
    【解决方案3】:

    即使在通用约束中没有指定构造函数,也可以调用它。请参阅下面的示例。

        'This base class has no constructor except the default empty one
    Public Class MyBaseClass
    
    End Class
    
    'this class inhetits MyBaseType, but it also implements a non empty constructor
    Public Class MySpecializedClass
        Inherits MyBaseClass
        Public Sub New(argument As String)
    
        End Sub
    End Class
    
    Public Function CreateObject(Of ClassType As MyBaseClass)(argument As String) As ClassType
        'First, get the item type:
        Dim itemType As Type = GetType(ClassType)
        'Now we can use the desired constructor:
        Dim constructor As ConstructorInfo = itemType.GetConstructor(New Type() {GetType(String)})
        If constructor Is Nothing Then
            Throw New InvalidConstraintException("Constructor ""New(String)"" not found.")
        Else
            Dim result As ClassType = constructor.Invoke(New Object() {argument})
            Return result
        End If
    End Function
    
    Public Sub RunTest()
        Try
            Console.WriteLine("+----------------------------------------------------+")
            Console.WriteLine("Trying to create a instance of MyBaseClass")
            Console.WriteLine("+----------------------------------------------------+")
            Dim myobject As MyBaseClass = CreateObject(Of MyBaseClass)("string value")
            Console.WriteLine(myobject)
            Console.WriteLine("Instance of MyBaseClass created")
        Catch ex As Exception
            Console.WriteLine(ex)
        End Try
        Try
            Console.WriteLine("+----------------------------------------------------+")
            Console.WriteLine("Trying to create a instance of MySpecializedClass")
            Console.WriteLine("+----------------------------------------------------+")
            Dim myobject As MyBaseClass = CreateObject(Of MySpecializedClass)("string value")
            Console.WriteLine(myobject)
            Console.WriteLine("Instance of MySpecializedClass created")
        Catch ex As Exception
            Console.WriteLine(ex)
        End Try
    End Sub
    

    【讨论】:

    • 使用反射很有趣。我的构造函数涉及一个接口;不确定GetType(T).GetConstructor(New Type() { ITheInterface }) 部分将如何处理这个问题,但我很乐观!
    【解决方案4】:

    这是我的答案。

    Public CreateObject(Of T)() As T
        Dim newObj = Activator.CreateInstance(GetType(T), YourParameterHere)
        Return newObj
    End Function
    

    这将为您提供新对象。您可以将任何参数传递给此函数。

    【讨论】:

      猜你喜欢
      • 2017-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-22
      • 2019-09-19
      • 2012-01-29
      • 1970-01-01
      相关资源
      最近更新 更多