10
votes

vb.net: appeler constructeur lors de l'utilisation de génériques

Je ne suis pas sûr que cela soit possible ou non.

J'ai un certain nombre de classes différentes qui implémentent l'interface IBAR et ont des constructeurs qui prennent quelques valeurs. Plutôt que de créer un tas de méthode presque identique, est-il possible d'avoir une méthode générique qui créera le constructeur approprié? xxx

i get: xxx


0 commentaires

3 Réponses :


13
votes

Malheureusement pas - Les génériques .NET ne vous permettent que de contraindre un type générique pour avoir un constructeur sans paramètre, que vous pouvez ensuite appeler avec nouveau t () ... Vous ne pouvez pas spécifier un particulier ensemble de paramètres.

Si cela ne vous dérange pas de faire de vos types mutable, vous pouvez créer une interface qui contenant une méthode avec les paramètres pertinents, permettez à tous vos types d'implémenter l'interface, puis contraignez le type à mettre en œuvre. cette méthode et avoir un constructeur sans paramètre, mais ce n'est pas idéal.

Une autre option consiste à transmettre dans un approprié> Func qui prend x et p1 et renvoie un nouveau t chaque fois. Cela serait certainement facile à utiliser à partir de C # - pas tout à fait si facile dans la VB IIRC, mais la peine d'être envisagée néanmoins.


4 commentaires

FUNC est OK maintenant dans vb.net. C'est encore plus verbeux qu'en C # cependant.


@Toddmo: Cela fonctionnera si vous contraindrez le type générique à avoir un constructeur sans paramètre . Cela ne fonctionnera pas si vous n'avez pas cette contrainte.


@Jonskeet, si vous aviez écrit Sub FOO (de T comme {myClass, nouveau}) Pour montrer ce que vous vouliez dire, je n'aurais pas été confus. Vous avez dit quelque chose mais ne l'a pas illustré. Merci.


En ce qui concerne la première option que vous avez mentionnée: suggérez-vous de créer l'objet via un constructeur sans paramètre, puis exécutez ensuite une fonction qui ferait le travail censé être fait à l'intérieur du constructeur complet de paramètres d'origine ? En d'autres termes, quelque chose comme getfoo (de T comme ibar) (P1, P2): ...: DIM Barre en tant que nouveau t: bar.finishConstruction (x, p1) (où finalconstruction fait partie de ibar , qui est implémenté par bar )?



7
votes

Développement de la réponse de Jon Skeet, voici une solution possible à l'aide d'un paramètre Func : xxx

utilisation serait similaire à xxx < / pré>


3 commentaires

Lorsque j'essaie de créer une fonction barimpl (i, o) comme foo {retournez nouvelle foo (i, o)}, alors je reçois une erreur lorsque vous appelez getfoo qui dit Barimpl n'est pas défini.


Barimpl est une classe implémentant ibar , pas une fonction


C'est une idée brillante d'utiliser des méthodes d'usine. Il est probablement préférable des constructeurs aussi une fois qu'il est en place, car vous pourriez penser comme injecter un état dans votre méthode de construction que vous ne pouvez pas faire dans le véritable constructeur.



3
votes

Il est possible de cal, un constructeur même s'il n'est pas spécifié dans des contraintes génériques. Voir l'exemple ci-dessous.

    '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


1 commentaires

Intéressant d'utiliser la réflexion. Mon constructeur implique une interface; Je ne sais pas comment le gettype (t) .getConstructor (nouveau type () {itheinterface}) se passe pour gérer cela, mais je suis optimiste!