Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les méthodes d’extension permettent aux développeurs d’ajouter des fonctionnalités personnalisées aux types de données déjà définis sans créer de nouveau type dérivé. Les méthodes d’extension permettent d’écrire une méthode qui peut être appelée comme s’il s’agissait d’une méthode d’instance du type existant.
Remarques
Une méthode d’extension ne peut être qu’une Sub
procédure ou une Function
procédure. Vous ne pouvez pas définir une propriété d’extension, un champ ou un événement. Toutes les méthodes d’extension doivent être marquées avec l’attribut <Extension>
d’extension de l’espace System.Runtime.CompilerServices de noms et doivent être définies dans un module. Si une méthode d’extension est définie en dehors d’un module, le compilateur Visual Basic génère une erreur BC36551, « Les méthodes d’extension ne peuvent être définies que dans les modules ».
Le premier paramètre d’une définition de méthode d’extension spécifie le type de données étendu par la méthode. Lorsque la méthode est exécutée, le premier paramètre est lié à l’instance du type de données qui appelle la méthode.
L’attribut Extension
ne peut être appliqué qu’à un Visual Basic Module
, Sub
ou Function
. Si vous l’appliquez à un ou à un Class
Structure
, le compilateur Visual Basic génère des erreurs BC36550, l’attribut « Extension » ne peut être appliqué qu’aux déclarations « Module », « Sub » ou « Function ».
Exemple :
L’exemple suivant définit une Print
extension au type de String données. La méthode utilise Console.WriteLine
pour afficher une chaîne. Le paramètre de la Print
méthode, aString
établit que la méthode étend la String classe.
Imports System.Runtime.CompilerServices
Module StringExtensions
<Extension()>
Public Sub Print(ByVal aString As String)
Console.WriteLine(aString)
End Sub
End Module
Notez que la définition de la méthode d’extension est marquée avec l’attribut <Extension()>
d’extension . Marquage du module dans lequel la méthode est définie est facultatif, mais chaque méthode d’extension doit être marquée.
System.Runtime.CompilerServices doit être importé pour accéder à l’attribut d’extension.
Les méthodes d’extension peuvent être déclarées uniquement dans les modules. En règle générale, le module dans lequel une méthode d’extension est définie n’est pas le même que celui dans lequel elle est appelée. Au lieu de cela, le module qui contient la méthode d’extension est importé, s’il doit l’être, pour l’intégrer dans l’étendue. Une fois que le module qui contient Print
est dans l’étendue, la méthode peut être appelée comme s’il s’agissait d’une méthode d’instance ordinaire qui ne prend aucun argument, par ToUpper
exemple :
Module Class1
Sub Main()
Dim example As String = "Hello"
' Call to extension method Print.
example.Print()
' Call to instance method ToUpper.
example.ToUpper()
example.ToUpper.Print()
End Sub
End Module
L’exemple suivant, PrintAndPunctuate
est également une extension à String, cette fois définie avec deux paramètres. Le premier paramètre, aString
établit que la méthode d’extension s’étend String. Le deuxième paramètre, punc
est destiné à être une chaîne de marques de ponctuation passées en tant qu’argument lorsque la méthode est appelée. La méthode affiche la chaîne suivie des marques de ponctuation.
<Extension()>
Public Sub PrintAndPunctuate(ByVal aString As String,
ByVal punc As String)
Console.WriteLine(aString & punc)
End Sub
La méthode est appelée en envoyant un argument de chaîne pour punc
: example.PrintAndPunctuate(".")
L’exemple suivant montre Print
et définit et PrintAndPunctuate
appelé.
System.Runtime.CompilerServices est importé dans le module de définition pour permettre l’accès à l’attribut d’extension.
Imports System.Runtime.CompilerServices
Module StringExtensions
<Extension()>
Public Sub Print(aString As String)
Console.WriteLine(aString)
End Sub
<Extension()>
Public Sub PrintAndPunctuate(aString As String, punc As String)
Console.WriteLine(aString & punc)
End Sub
End Module
Ensuite, les méthodes d’extension sont introduites dans l’étendue et appelées :
Imports ConsoleApplication2.StringExtensions
Module Module1
Sub Main()
Dim example As String = "Example string"
example.Print()
example = "Hello"
example.PrintAndPunctuate(".")
example.PrintAndPunctuate("!!!!")
End Sub
End Module
Tout ce qui est nécessaire pour pouvoir exécuter ces méthodes d’extension ou similaires est qu’elles sont dans l’étendue. Si le module qui contient une méthode d’extension est dans l’étendue, il est visible dans IntelliSense et peut être appelé comme s’il s’agissait d’une méthode d’instance ordinaire.
Notez que lorsque les méthodes sont appelées, aucun argument n’est envoyé pour le premier paramètre. Le paramètre aString
dans les définitions de méthode précédentes est lié à example
, l’instance de String
ce dernier les appelle. Le compilateur utilise example
comme argument envoyé au premier paramètre.
Si une méthode d’extension est appelée pour un objet défini Nothing
sur , la méthode d’extension s’exécute. Cela ne s’applique pas aux méthodes d’instance ordinaires. Vous pouvez rechercher Nothing
explicitement dans la méthode d’extension.
Types pouvant être étendus
Vous pouvez définir une méthode d’extension sur la plupart des types qui peuvent être représentés dans une liste de paramètres Visual Basic, y compris les éléments suivants :
- Classes (types de référence)
- Structures (types valeur)
- Interfaces
- Délégués
- Arguments ByRef et ByVal
- Paramètres de méthode générique
- Tableaux
Étant donné que le premier paramètre spécifie le type de données étendu par la méthode d’extension, il est requis et ne peut pas être facultatif. Pour cette raison, Optional
les paramètres et ParamArray
les paramètres ne peuvent pas être le premier paramètre de la liste des paramètres.
Les méthodes d’extension ne sont pas prises en compte dans la liaison tardive. Dans l’exemple suivant, l’instruction anObject.PrintMe()
déclenche une MissingMemberException exception, la même exception que celle que vous verrez si la deuxième PrintMe
définition de méthode d’extension a été supprimée.
Option Strict Off
Imports System.Runtime.CompilerServices
Module Module4
Sub Main()
Dim aString As String = "Initial value for aString"
aString.PrintMe()
Dim anObject As Object = "Initial value for anObject"
' The following statement causes a run-time error when Option
' Strict is off, and a compiler error when Option Strict is on.
'anObject.PrintMe()
End Sub
<Extension()>
Public Sub PrintMe(ByVal str As String)
Console.WriteLine(str)
End Sub
<Extension()>
Public Sub PrintMe(ByVal obj As Object)
Console.WriteLine(obj)
End Sub
End Module
Meilleures pratiques
Les méthodes d’extension offrent un moyen pratique et puissant d’étendre un type existant. Toutefois, pour les utiliser avec succès, il existe quelques points à prendre en compte. Ces considérations s’appliquent principalement aux auteurs de bibliothèques de classes, mais elles peuvent affecter toute application qui utilise des méthodes d’extension.
En règle générale, les méthodes d’extension que vous ajoutez aux types que vous ne possédez pas sont plus vulnérables que les méthodes d’extension ajoutées aux types que vous contrôlez. Un certain nombre de choses peuvent se produire dans les classes que vous ne possédez pas qui peuvent interférer avec vos méthodes d’extension.
Si un membre d’instance accessible existe qui a une signature compatible avec les arguments de l’instruction appelante, sans conversions restrictives requises d’argument en paramètre, la méthode d’instance sera utilisée en préférence pour toute méthode d’extension. Par conséquent, si une méthode d’instance appropriée est ajoutée à une classe à un moment donné, un membre d’extension existant sur lequel vous vous appuyez peut devenir inaccessible.
L’auteur d’une méthode d’extension ne peut pas empêcher d’autres programmeurs d’écrire des méthodes d’extension en conflit qui peuvent avoir la priorité sur l’extension d’origine.
Vous pouvez améliorer la robustesse en plaçant les méthodes d’extension dans leur propre espace de noms. Les consommateurs de votre bibliothèque peuvent ensuite inclure un espace de noms ou l’exclure, ou sélectionner parmi les espaces de noms, séparément du reste de la bibliothèque.
Il peut être plus sûr d’étendre les interfaces qu’il ne s’agit d’étendre des classes, en particulier si vous ne possédez pas l’interface ou la classe. Une modification dans une interface affecte chaque classe qui l’implémente. Par conséquent, l’auteur peut être moins susceptible d’ajouter ou de modifier des méthodes dans une interface. Toutefois, si une classe implémente deux interfaces qui ont des méthodes d’extension avec la même signature, aucune méthode d’extension n’est visible.
Étendez le type le plus spécifique que vous pouvez. Dans une hiérarchie de types, si vous sélectionnez un type à partir duquel de nombreux autres types sont dérivés, il existe des couches de possibilités pour l’introduction de méthodes d’instance ou d’autres méthodes d’extension susceptibles d’interférer avec le vôtre.
Méthodes d’extension, méthodes d’instance et propriétés
Lorsqu’une méthode d’instance dans l’étendue a une signature compatible avec les arguments d’une instruction appelante, la méthode d’instance est choisie en préférence pour n’importe quelle méthode d’extension. La méthode d’instance est prioritaire même si la méthode d’extension est une meilleure correspondance. Dans l’exemple suivant, ExampleClass
contient une méthode d’instance nommée ExampleMethod
qui a un paramètre de type Integer
. La méthode ExampleMethod
d’extension s’étend ExampleClass
et a un paramètre de type Long
.
Class ExampleClass
' Define an instance method named ExampleMethod.
Public Sub ExampleMethod(ByVal m As Integer)
Console.WriteLine("Instance method")
End Sub
End Class
<Extension()>
Sub ExampleMethod(ByVal ec As ExampleClass,
ByVal n As Long)
Console.WriteLine("Extension method")
End Sub
Le premier appel au ExampleMethod
code suivant appelle la méthode d’extension, car arg1
il est Long
compatible uniquement avec le Long
paramètre de la méthode d’extension. Le deuxième appel à avoir ExampleMethod
un Integer
argument, arg2
et il appelle la méthode d’instance.
Sub Main()
Dim example As New ExampleClass
Dim arg1 As Long = 10
Dim arg2 As Integer = 5
' The following statement calls the extension method.
example.exampleMethod(arg1)
' The following statement calls the instance method.
example.exampleMethod(arg2)
End Sub
À présent, inversez les types de données des paramètres dans les deux méthodes :
Class ExampleClass
' Define an instance method named ExampleMethod.
Public Sub ExampleMethod(ByVal m As Long)
Console.WriteLine("Instance method")
End Sub
End Class
<Extension()>
Sub ExampleMethod(ByVal ec As ExampleClass,
ByVal n As Integer)
Console.WriteLine("Extension method")
End Sub
Cette fois, le code dans appelle Main
la méthode d’instance deux fois. Cela est dû au fait que les deux arg1
et arg2
ont une conversion étendue en Long
, et la méthode d’instance est prioritaire sur la méthode d’extension dans les deux cas.
Sub Main()
Dim example As New ExampleClass
Dim arg1 As Long = 10
Dim arg2 As Integer = 5
' The following statement calls the instance method.
example.ExampleMethod(arg1)
' The following statement calls the instance method.
example.ExampleMethod(arg2)
End Sub
Par conséquent, une méthode d’extension ne peut pas remplacer une méthode d’instance existante. Toutefois, lorsqu’une méthode d’extension porte le même nom qu’une méthode d’instance, mais que les signatures ne sont pas en conflit, les deux méthodes sont accessibles. Par exemple, si la classe ExampleClass
contient une méthode nommée ExampleMethod
qui ne prend aucun argument, les méthodes d’extension portant le même nom, mais différentes signatures sont autorisées, comme indiqué dans le code suivant.
Imports System.Runtime.CompilerServices
Module Module3
Sub Main()
Dim ex As New ExampleClass
' The following statement calls the extension method.
ex.ExampleMethod("Extension method")
' The following statement calls the instance method.
ex.ExampleMethod()
End Sub
Class ExampleClass
' Define an instance method named ExampleMethod.
Public Sub ExampleMethod()
Console.WriteLine("Instance method")
End Sub
End Class
<Extension()>
Sub ExampleMethod(ByVal ec As ExampleClass,
ByVal stringParameter As String)
Console.WriteLine(stringParameter)
End Sub
End Module
La sortie de ce code est la suivante :
Extension method
Instance method
La situation est plus simple avec les propriétés : si une méthode d’extension porte le même nom qu’une propriété de la classe qu’elle étend, la méthode d’extension n’est pas visible et n’est pas accessible.
Priorité des méthodes d’extension
Lorsque deux méthodes d’extension qui ont des signatures identiques sont dans l’étendue et accessibles, celle avec une priorité plus élevée est appelée. La priorité d’une méthode d’extension est basée sur le mécanisme utilisé pour placer la méthode dans l’étendue. La liste suivante montre la hiérarchie de précédence, de la plus haute à la plus basse.
Méthodes d’extension définies à l’intérieur du module actuel.
Méthodes d’extension définies à l’intérieur des types de données dans l’espace de noms actuel ou l’un de ses parents, avec des espaces de noms enfants ayant une priorité plus élevée que les espaces de noms parents.
Méthodes d’extension définies à l’intérieur de n’importe quel type importe dans le fichier actif.
Méthodes d’extension définies à l’intérieur d’un espace de noms importe dans le fichier actif.
Méthodes d’extension définies à l’intérieur d’une importation de type au niveau du projet.
Méthodes d’extension définies dans les importations d’espaces de noms au niveau du projet.
Si la priorité ne résout pas l’ambiguïté, vous pouvez utiliser le nom complet pour spécifier la méthode que vous appelez. Si la Print
méthode de l’exemple précédent est définie dans un module nommé StringExtensions
, le nom complet est StringExtensions.Print(example)
au lieu de example.Print()
.