39 votes

VB.NET : impossible d'utiliser la méthode Extension sur une instance System.Object

Puis-je faire une méthode Extension pour toutes les sous-classes de System.Object (tout) ?

Exemple :

<Extension>
Public Function MyExtension(value As Object) As Object
    Return value
End Function

Les fonctions ci-dessus ne fonctionneront pas pour l'instance objet :

Dim myObj1 As New Object()
Dim myObj2 = myObj1.MyExtension()

Le compilateur ne l'accepte pas, le problème est-il dans mon ordinateur ? :)

UPDATE
Le problème semble se produire uniquement en VB, où les membres de l'objet sont consultés par réflexion ( en retard ).

MISE À JOUR APRÈS RÉPONSE
Pour votre information, vb a un avantage que C# n'a pas, à savoir que les membres des modules importés sont importés dans la portée globale, ce qui vous permet d'utiliser ces fonctions sans leur enveloppe :

Dim myObj2 = MyExtension(myObj1)

0 votes

1) C'est maintenant possible en C# avec la fonction using static <namespace.type> pour importer des membres dans la portée actuelle. 2) Le problème semble se produire uniquement en VB, où les membres de l'objet sont consultés par réflexion. N'est-ce pas seulement vrai si Option Strict Off ?

46voto

jdot Points 530

Il semble que le fait de ne pas supporter les méthodes d'extension sur les objets ait été une décision de conception dans VB.

Par conséquent, le seul moyen que nous avions empêcher les méthodes d'extension de de casser complètement le code existant lié existant était de les empêcher d'être être utilisées sur tout ce qui est typé objet.

http://blogs.msdn.com/b/vbteam/archive/2007/01/24/extension-methods-and-late-binding-extension-methods-part-4.aspx

1 votes

Réponse accréditée pour avoir fourni le lien source Microsoft.

14voto

Dan Tao Points 60518

Voir cette question que j'ai posée il y a quelque temps . En gros, vous peut étendre Object en VB.NET si vous le souhaitez ; mais pour des raisons de rétrocompatibilité, aucune variable déclaré comme Object sera en mesure d'utiliser votre méthode d'extension. En effet, VB.NET prend en charge la liaison tardive sur les éléments suivants Object Ainsi, une tentative d'accès à une méthode d'extension sera ignorée au profit de la recherche d'une méthode du même nom dans le type de l'objet en question.

Prenons par exemple cette méthode d'extension :

<Extension()>
Public Sub Dump(ByVal obj As Object)
    Console.WriteLine(obj)
End Sub

Cette méthode d'extension pourrait être utilisée ici :

' Note: here we are calling the Dump extension method on a variable '
' typed as String, which works because String (like all classes) '
' inherits from Object. '
Dim str As String = "Hello!"
str.Dump()

Mais pas ici :

' Here we attempt to call Dump on a variable typed as Object; but '
' this will not work since late binding is a feature that came before '
' extension methods. '
Dim obj As New Object
obj.Dump()

Demandez vous pourquoi les méthodes d'extension ne fonctionnent pas sur dynamic variables en C#, et vous réaliserez que l'explication est la même.

13voto

jmoreno Points 6995

Vous ne pouvez pas directement écrire une méthode d'extension pour Object, mais en utilisant les génériques vous pouvez obtenir le même résultat :

<Extension()>
Public Function NullSafeToString(Of T)(this As T) As String
    If this is Nothing Then
       Return String.Empty
    End If
    Return this.ToString()
End Function

Notez que vous pouvez appeler cette méthode en tant que méthode d'extension sur tout ce que vous voulez sauf les choses qui sont déclarées comme ayant le type Object. Pour ceux-là, vous devez soit l'appeler directement (preuve complète), soit l'appeler via un casting (ce qui peut échouer, car il n'y a pas d'interface univoque, donc un peu aléatoire).

1voto

miroxlav Points 1201

La réponse de jmoreno ne peut être utilisé avec Option Strict On - une erreur se produit :

BC30512 Option Strict On interdit les conversions implicites de 'Object' à 'Integer'.

Il faut passer du contexte de la classe au module d'extension :

Dim text1 As String = MyExtModule.NullSafeToString(DataGridView1.Rows(0).Cells(0).Value)

0voto

mattmc3 Points 6768

Bien sûr que vous pouvez le faire, mais vous devriez faire attention à ce que vous faites ici afin de ne pas encombrer chaque objet. Une méthode d'extension que j'aime utiliser pour Object est une méthode appelée IsIn() qui fonctionne de manière similaire à l'instruction SQL IN(). Il est agréable de dire des choses comme :

If someString.IsIn("a", "b", "c") Then
   DoSomething()
Else If someInt.IsIn(1, 2, 3) Then
   DoSomethingElse()
Else If someObj.IsIn(1, "q", #7/1/2010#) Then
   DoSomethingTheThirdWay()
End If

EDIT -

Ajout de l'implémentation de la méthode d'extension IsIn() ci-dessous pour aider le commentateur.

Imports System.Runtime.CompilerServices

Public Module ObjectExtensions
  <Extension()>
  Public Function IsIn(obj As Object, ParamArray values() As Object) As Boolean
    For Each val As Object In values
      If val.Equals(obj) Then Return True
    Next
    Return False
  End Function
End Module

2 votes

Avez-vous testé ce code ? La troisième ligne (someObj) ne fonctionne pas pour moi.

0 votes

Oui, ça marche pour moi. Comment avez-vous écrit votre version de la méthode d'extension IsIn() ? J'ai modifié mon message pour inclure mon implémentation afin de vous aider.

4 votes

Si vous avez tapé someObj comme Object dans votre code, alors ceci devrait définitivement no travailler pour vous.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X