Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

vb.net: calling constructor when using generics

I'm not sure if this is possible or not.

I have a number of different classes that implement interface IBar, and have constructors that take a couple of values. Rather than create a bunch of almost identical method, is it possible to have a generic method that will create the appropriate constructor?

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

I get:

'New' cannot be used on a type parameter that does not have a 'New' constraint. 
like image 881
chris Avatar asked Mar 09 '11 20:03

chris


3 Answers

Unfortunately not - .NET generics only allow you to constrain a generic type to have a parameterless constructor, which you can then call with New T()... you can't specify a particular set of parameters.

If you don't mind making your types mutable, you could create an interface which containing a method with the relevant parameters, make all your types implement the interface, and then constrain the type to implement that method and have a parameterless constructor, but it's not ideal.

Another option is to pass in an appropriate Func which takes x and p1 and returns a new T each time. That would certainly be easy to use from C# - not quite so easy in VB IIRC, but worth considering nevertheless.

like image 158
Jon Skeet Avatar answered Nov 12 '22 18:11

Jon Skeet


Expanding on Jon Skeet's answer, here's a possible solution using a Func parameter:

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

usage would be similar to

    GetFoo(1, 2, Function(i, o) New BarImpl(i, o))
like image 33
jeroenh Avatar answered Nov 12 '22 16:11

jeroenh


It is possible to cal, a constructor even if it is not specified in generic constraints. See the example below.

    '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
like image 3
Henrique Avatar answered Nov 12 '22 17:11

Henrique