Note
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier les répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de changer de répertoire.
Les tableaux sont des collections mutables de taille fixe, de base zéro et mutables d’éléments de données consécutifs qui sont tous du même type.
Créer des tableaux
Vous pouvez créer des tableaux de plusieurs façons. Vous pouvez créer un petit tableau en répertoriant les valeurs consécutives entre [| et |] séparées par des points-virgules, comme indiqué dans les exemples suivants.
let array1 = [| 1; 2; 3 |]
Vous pouvez également placer chaque élément sur une ligne distincte, auquel cas le séparateur de points-virgules est facultatif.
let array1 =
[|
1
2
3
|]
Le type des éléments de tableau est déduit des littéraux utilisés et doit être cohérent.
// This is an array of 3 integers.
let array1 = [| 1; 2; 3 |]
// This is an array of a tuple of 3 integers.
let array2 = [| 1, 2, 3 |]
Le code suivant provoque une erreur, car 3.0 est un float et 1 et 2 sont des entiers.
// Causes an error. The 3.0 (float) cannot be converted to integer implicitly.
// let array3 = [| 1; 2; 3.0 |]
Le code suivant provoque également une erreur, car 1,2 il s’agit d’un tuple et 3 est un entier.
// Causes an error too. The 3 (integer) cannot be converted to tuple implicitly.
// let array4 = [| 1, 2; 3 |]
Vous pouvez également utiliser des expressions de séquence pour créer des tableaux. Voici un exemple qui crée un tableau de carrés d’entiers compris entre 1 et 10.
let array3 = [| for i in 1 .. 10 -> i * i |]
Pour créer un tableau dans lequel tous les éléments sont initialisés sur zéro, utilisez Array.zeroCreate.
let arrayOfTenZeroes : int array = Array.zeroCreate 10
Éléments Access
Vous pouvez accéder aux éléments de tableau à l’aide de crochets ([ et ]). La syntaxe de point d’origine (.[index]) est toujours prise en charge, mais n’est plus recommandée à partir de F# 6.0.
array1[0]
Les index de tableau commencent à 0.
Vous pouvez également accéder aux éléments de tableau à l’aide de la notation de tranche, ce qui vous permet de spécifier une sous-plage du tableau. Voici des exemples de notation de tranche.
// Accesses elements from 0 to 2.
array1[0..2]
// Accesses elements from the beginning of the array to 2.
array1[..2]
// Accesses elements from 2 to the end of the array.
array1[2..]
Lorsque la notation de tranche est utilisée, une nouvelle copie du tableau est créée.
Types de tableaux et modules
Le type de tous les tableaux F# est le type System.Array.NET Framework. Par conséquent, les tableaux F# prennent en charge toutes les fonctionnalités disponibles dans System.Array.
Le Array module prend en charge les opérations sur des tableaux unidimensionnels. Les modules Array2D, Array3Det Array4D contiennent des fonctions qui prennent en charge les opérations sur des tableaux de deux, trois et quatre dimensions, respectivement. Vous pouvez créer des tableaux de rang supérieur à quatre à l’aide System.Arrayde .
Fonctions simples
Array.get obtient un élément.
Array.length donne la longueur d’un tableau.
Array.set définit un élément sur une valeur spécifiée. L’exemple de code suivant illustre l’utilisation de ces fonctions.
let array1 = Array.create 10 ""
for i in 0 .. array1.Length - 1 do
Array.set array1 i (i.ToString())
for i in 0 .. array1.Length - 1 do
printf "%s " (Array.get array1 i)
La sortie est la suivante.
0 1 2 3 4 5 6 7 8 9
Fonctions qui créent des tableaux
Plusieurs fonctions créent des tableaux sans nécessiter de tableau existant.
Array.empty crée un tableau qui ne contient aucun élément.
Array.create crée un tableau d’une taille spécifiée et définit tous les éléments sur des valeurs fournies.
Array.init crée un tableau, en fonction d’une dimension et d’une fonction pour générer les éléments.
Array.zeroCreate crée un tableau dans lequel tous les éléments sont initialisés à la valeur zéro pour le type du tableau. Le code suivant illustre ces fonctions.
let myEmptyArray = Array.empty
printfn "Length of empty array: %d" myEmptyArray.Length
printfn "Array of floats set to 5.0: %A" (Array.create 10 5.0)
printfn "Array of squares: %A" (Array.init 10 (fun index -> index * index))
let (myZeroArray : float array) = Array.zeroCreate 10
La sortie est la suivante.
Length of empty array: 0
Area of floats set to 5.0: [|5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0; 5.0|]
Array of squares: [|0; 1; 4; 9; 16; 25; 36; 49; 64; 81|]
Array.copy crée un tableau qui contient des éléments copiés à partir d’un tableau existant. Notez que la copie est une copie superficielle, ce qui signifie que si le type d’élément est un type référence, seule la référence est copiée, et non l’objet sous-jacent. L’exemple de code suivant illustre cela.
open System.Text
let firstArray : StringBuilder array = Array.init 3 (fun index -> new StringBuilder(""))
let secondArray = Array.copy firstArray
// Reset an element of the first array to a new value.
firstArray[0] <- new StringBuilder("Test1")
// Change an element of the first array.
firstArray[1].Insert(0, "Test2") |> ignore
printfn "%A" firstArray
printfn "%A" secondArray
La sortie du code précédent est la suivante :
[|Test1; Test2; |]
[|; Test2; |]
La chaîne Test1 apparaît uniquement dans le premier tableau, car l’opération de création d’un nouvel élément remplace la référence dans firstArray laquelle elle n’affecte pas la référence d’origine à une chaîne vide qui est toujours présente dans secondArray. La chaîne Test2 apparaît dans les deux tableaux, car l’opération Insert sur le System.Text.StringBuilder type affecte l’objet sous-jacent System.Text.StringBuilder , qui est référencé dans les deux tableaux.
Array.sub génère un nouveau tableau à partir d’une sous-plage d’un tableau. Vous spécifiez la sous-plage en fournissant l’index de départ et la longueur. Le code suivant illustre l’utilisation de Array.sub.
let a1 = [| 0 .. 99 |]
let a2 = Array.sub a1 5 10
printfn "%A" a2
La sortie indique que le sous-tableau commence à l’élément 5 et contient 10 éléments.
[|5; 6; 7; 8; 9; 10; 11; 12; 13; 14|]
Array.append crée un tableau en combinant deux tableaux existants.
Le code suivant illustre Array.append.
printfn "%A" (Array.append [| 1; 2; 3|] [| 4; 5; 6|])
La sortie du code précédent est la suivante.
[|1; 2; 3; 4; 5; 6|]
Array.choose sélectionne les éléments d’un tableau à inclure dans un nouveau tableau. Le code suivant illustre Array.choose. Notez que le type d’élément du tableau n’a pas besoin de correspondre au type de la valeur retournée dans le type d’option. Dans cet exemple, le type d’élément est int et l’option est le résultat d’une fonction polynomiale, elem*elem - 1en tant que nombre à virgule flottante.
printfn "%A" (Array.choose (fun elem -> if elem % 2 = 0 then
Some(float (elem*elem - 1))
else
None) [| 1 .. 10 |])
La sortie du code précédent est la suivante.
[|3.0; 15.0; 35.0; 63.0; 99.0|]
Array.collect exécute une fonction spécifiée sur chaque élément de tableau d’un tableau existant, puis collecte les éléments générés par la fonction et les combine dans un nouveau tableau. Le code suivant illustre Array.collect.
printfn "%A" (Array.collect (fun elem -> [| 0 .. elem |]) [| 1; 5; 10|])
La sortie du code précédent est la suivante.
[|0; 1; 0; 1; 2; 3; 4; 5; 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]
Array.concat prend une séquence de tableaux et les combine dans un tableau unique. Le code suivant illustre Array.concat.
Array.concat [ [|0..3|] ; [|4|] ]
//output [|0; 1; 2; 3; 4|]
Array.concat [| [|0..3|] ; [|4|] |]
//output [|0; 1; 2; 3; 4|]
Array.filter prend une fonction de condition booléenne et génère un nouveau tableau qui contient uniquement les éléments du tableau d’entrée pour lequel la condition est vraie. Le code suivant illustre Array.filter.
printfn "%A" (Array.filter (fun elem -> elem % 2 = 0) [| 1 .. 10|])
La sortie du code précédent est la suivante.
[|2; 4; 6; 8; 10|]
Array.rev génère un nouveau tableau en inversant l’ordre d’un tableau existant. Le code suivant illustre Array.rev.
let stringReverse (s: string) =
System.String(Array.rev (s.ToCharArray()))
printfn "%A" (stringReverse("!dlrow olleH"))
La sortie du code précédent est la suivante.
"Hello world!"
Vous pouvez facilement combiner des fonctions dans le module de tableau qui transforment des tableaux à l’aide de l’opérateur de pipeline (|>), comme illustré dans l’exemple suivant.
[| 1 .. 10 |]
|> Array.filter (fun elem -> elem % 2 = 0)
|> Array.choose (fun elem -> if (elem <> 8) then Some(elem*elem) else None)
|> Array.rev
|> printfn "%A"
La sortie est
[|100; 36; 16; 4|]
Tableaux multidimensionnels
Un tableau multidimensionnel peut être créé, mais il n’existe aucune syntaxe pour écrire un littéral de tableau multidimensionnel. Utilisez l’opérateur array2D pour créer un tableau à partir d’une séquence de séquences d’éléments de tableau. Les séquences peuvent être des littéraux de tableau ou de liste. Par exemple, le code suivant crée un tableau à deux dimensions.
let my2DArray = array2D [ [ 1; 0]; [0; 1] ]
Vous pouvez également utiliser la fonction Array2D.init pour initialiser des tableaux de deux dimensions, et des fonctions similaires sont disponibles pour les tableaux de trois et quatre dimensions. Ces fonctions prennent une fonction utilisée pour créer les éléments. Pour créer un tableau à deux dimensions qui contient des éléments définis sur une valeur initiale au lieu de spécifier une fonction, utilisez la Array2D.create fonction, qui est également disponible pour les tableaux jusqu’à quatre dimensions. L’exemple de code suivant montre tout d’abord comment créer un tableau de tableaux qui contiennent les éléments souhaités, puis l’utilise Array2D.init pour générer le tableau bidimensionnel souhaité.
let arrayOfArrays = [| [| 1.0; 0.0 |]; [|0.0; 1.0 |] |]
let twoDimensionalArray = Array2D.init 2 2 (fun i j -> arrayOfArrays[i][j])
La syntaxe d’indexation et de découpage des tableaux est prise en charge pour les tableaux pouvant atteindre le rang 4. Lorsque vous spécifiez un index dans plusieurs dimensions, vous utilisez des virgules pour séparer les index, comme illustré dans l’exemple de code suivant.
twoDimensionalArray[0, 1] <- 1.0
Le type d’un tableau à deux dimensions est écrit comme <type>[,] (par exemple, int[,], double[,]), et le type d’un tableau à trois dimensions est écrit comme <type>[,,], et ainsi de suite pour les tableaux de dimensions supérieures.
Seul un sous-ensemble des fonctions disponibles pour les tableaux unidimensionnels est également disponible pour les tableaux multidimensionnels.
Découpage de tableau et tableaux multidimensionnels
Dans un tableau à deux dimensions (matrice), vous pouvez extraire une sous-matrice en spécifiant des plages et en utilisant un caractère générique (*) pour spécifier des lignes ou des colonnes entières.
// Get rows 1 to N from an NxM matrix (returns a matrix):
matrix[1.., *]
// Get rows 1 to 3 from a matrix (returns a matrix):
matrix[1..3, *]
// Get columns 1 to 3 from a matrix (returns a matrix):
matrix[*, 1..3]
// Get a 3x3 submatrix:
matrix[1..3, 1..3]
Vous pouvez décomposer un tableau multidimensionnel en sous-répertoires de la même ou de la même dimension inférieure. Par exemple, vous pouvez obtenir un vecteur à partir d’une matrice en spécifiant une seule ligne ou colonne.
// Get row 3 from a matrix as a vector:
matrix[3, *]
// Get column 3 from a matrix as a vector:
matrix[*, 3]
Vous pouvez utiliser cette syntaxe de découpage pour les types qui implémentent les opérateurs d’accès aux éléments et les méthodes surchargées GetSlice . Par exemple, le code suivant crée un type Matrix qui encapsule le tableau F# 2D, implémente une propriété Item pour prendre en charge l’indexation de tableaux et implémente trois versions de GetSlice. Si vous pouvez utiliser ce code comme modèle pour vos types de matrices, vous pouvez utiliser toutes les opérations de découpage décrites par cette section.
type Matrix<'T>(N: int, M: int) =
let internalArray = Array2D.zeroCreate<'T> N M
member this.Item
with get(a: int, b: int) = internalArray[a, b]
and set(a: int, b: int) (value:'T) = internalArray[a, b] <- value
member this.GetSlice(rowStart: int option, rowFinish : int option, colStart: int option, colFinish : int option) =
let rowStart =
match rowStart with
| Some(v) -> v
| None -> 0
let rowFinish =
match rowFinish with
| Some(v) -> v
| None -> internalArray.GetLength(0) - 1
let colStart =
match colStart with
| Some(v) -> v
| None -> 0
let colFinish =
match colFinish with
| Some(v) -> v
| None -> internalArray.GetLength(1) - 1
internalArray[rowStart..rowFinish, colStart..colFinish]
member this.GetSlice(row: int, colStart: int option, colFinish: int option) =
let colStart =
match colStart with
| Some(v) -> v
| None -> 0
let colFinish =
match colFinish with
| Some(v) -> v
| None -> internalArray.GetLength(1) - 1
internalArray[row, colStart..colFinish]
member this.GetSlice(rowStart: int option, rowFinish: int option, col: int) =
let rowStart =
match rowStart with
| Some(v) -> v
| None -> 0
let rowFinish =
match rowFinish with
| Some(v) -> v
| None -> internalArray.GetLength(0) - 1
internalArray[rowStart..rowFinish, col]
module test =
let generateTestMatrix x y =
let matrix = new Matrix<float>(3, 3)
for i in 0..2 do
for j in 0..2 do
matrix[i, j] <- float(i) * x - float(j) * y
matrix
let test1 = generateTestMatrix 2.3 1.1
let submatrix = test1[0..1, 0..1]
printfn $"{submatrix}"
let firstRow = test1[0,*]
let secondRow = test1[1,*]
let firstCol = test1[*,0]
printfn $"{firstCol}"
Fonctions booléennes sur les tableaux
Les fonctions Array.exists et Array.exists2 les éléments de test dans un ou deux tableaux, respectivement. Ces fonctions prennent une fonction de test et retournent true s’il existe un élément (ou une paire d’éléments pour Array.exists2) qui satisfait à la condition.
Le code suivant illustre l’utilisation de Array.exists et Array.exists2. Dans ces exemples, de nouvelles fonctions sont créées en appliquant un seul des arguments, dans ces cas, l’argument de fonction.
let allNegative = Array.exists (fun elem -> abs (elem) = elem) >> not
printfn "%A" (allNegative [| -1; -2; -3 |])
printfn "%A" (allNegative [| -10; -1; 5 |])
printfn "%A" (allNegative [| 0 |])
let haveEqualElement = Array.exists2 (fun elem1 elem2 -> elem1 = elem2)
printfn "%A" (haveEqualElement [| 1; 2; 3 |] [| 3; 2; 1|])
La sortie du code précédent est la suivante.
true
false
false
true
De même, la fonction Array.forall teste un tableau pour déterminer si chaque élément satisfait à une condition booléenne. La variante Array.forall2 fait la même chose à l’aide d’une fonction booléenne qui implique des éléments de deux tableaux de longueur égale. Le code suivant illustre l’utilisation de ces fonctions.
let allPositive = Array.forall (fun elem -> elem > 0)
printfn "%A" (allPositive [| 0; 1; 2; 3 |])
printfn "%A" (allPositive [| 1; 2; 3 |])
let allEqual = Array.forall2 (fun elem1 elem2 -> elem1 = elem2)
printfn "%A" (allEqual [| 1; 2 |] [| 1; 2 |])
printfn "%A" (allEqual [| 1; 2 |] [| 2; 1 |])
La sortie de ces exemples est la suivante.
false
true
true
false
Tableaux de recherche
Array.find prend une fonction booléenne et retourne le premier élément pour lequel la fonction retourne true, ou déclenche un System.Collections.Generic.KeyNotFoundException élément si aucun élément qui satisfait à la condition est trouvé.
Array.findIndex est semblable Array.find, sauf qu’il retourne l’index de l’élément au lieu de l’élément lui-même.
Le code suivant utilise Array.find et Array.findIndex pour localiser un nombre qui est à la fois un carré parfait et un cube parfait.
let arrayA = [| 2 .. 100 |]
let delta = 1.0e-10
let isPerfectSquare (x:int) =
let y = sqrt (float x)
abs(y - round y) < delta
let isPerfectCube (x:int) =
let y = System.Math.Pow(float x, 1.0/3.0)
abs(y - round y) < delta
let element = Array.find (fun elem -> isPerfectSquare elem && isPerfectCube elem) arrayA
let index = Array.findIndex (fun elem -> isPerfectSquare elem && isPerfectCube elem) arrayA
printfn "The first element that is both a square and a cube is %d and its index is %d." element index
La sortie est la suivante.
The first element that is both a square and a cube is 64 and its index is 62.
Array.tryFind est semblable Array.find, sauf que son résultat est un type d’option et qu’il retourne None si aucun élément n’est trouvé.
Array.tryFind doit être utilisé au lieu du moment où Array.find vous ne savez pas si un élément correspondant se trouve dans le tableau. De même, Array.tryFindIndex c’est comme Array.findIndex si le type d’option était la valeur de retour. Si aucun élément n’est trouvé, l’option est None.
Le code suivant illustre l’utilisation de Array.tryFind. Ce code dépend du code précédent.
let delta = 1.0e-10
let isPerfectSquare (x:int) =
let y = sqrt (float x)
abs(y - round y) < delta
let isPerfectCube (x:int) =
let y = System.Math.Pow(float x, 1.0/3.0)
abs(y - round y) < delta
let lookForCubeAndSquare array1 =
let result = Array.tryFind (fun elem -> isPerfectSquare elem && isPerfectCube elem) array1
match result with
| Some x -> printfn "Found an element: %d" x
| None -> printfn "Failed to find a matching element."
lookForCubeAndSquare [| 1 .. 10 |]
lookForCubeAndSquare [| 100 .. 1000 |]
lookForCubeAndSquare [| 2 .. 50 |]
La sortie est la suivante.
Found an element: 1
Found an element: 729
Failed to find a matching element.
Utilisez Array.tryPick quand vous devez transformer un élément en plus de le trouver. Le résultat est le premier élément pour lequel la fonction retourne l’élément transformé en tant que valeur d’option, ou None si aucun élément de ce type n’est trouvé.
Le code suivant montre l’utilisation de Array.tryPick. Dans ce cas, au lieu d’une expression lambda, plusieurs fonctions d’assistance locales sont définies pour simplifier le code.
let findPerfectSquareAndCube array1 =
let delta = 1.0e-10
let isPerfectSquare (x:int) =
let y = sqrt (float x)
abs(y - round y) < delta
let isPerfectCube (x:int) =
let y = System.Math.Pow(float x, 1.0/3.0)
abs(y - round y) < delta
// intFunction : (float -> float) -> int -> int
// Allows the use of a floating point function with integers.
let intFunction function1 number = int (round (function1 (float number)))
let cubeRoot x = System.Math.Pow(x, 1.0/3.0)
// testElement: int -> (int * int * int) option
// Test an element to see whether it is a perfect square and a perfect
// cube, and, if so, return the element, square root, and cube root
// as an option value. Otherwise, return None.
let testElement elem =
if isPerfectSquare elem && isPerfectCube elem then
Some(elem, intFunction sqrt elem, intFunction cubeRoot elem)
else None
match Array.tryPick testElement array1 with
| Some (n, sqrt, cuberoot) -> printfn "Found an element %d with square root %d and cube root %d." n sqrt cuberoot
| None -> printfn "Did not find an element that is both a perfect square and a perfect cube."
findPerfectSquareAndCube [| 1 .. 10 |]
findPerfectSquareAndCube [| 2 .. 100 |]
findPerfectSquareAndCube [| 100 .. 1000 |]
findPerfectSquareAndCube [| 1000 .. 10000 |]
findPerfectSquareAndCube [| 2 .. 50 |]
La sortie est la suivante.
Found an element 1 with square root 1 and cube root 1.
Found an element 64 with square root 8 and cube root 4.
Found an element 729 with square root 27 and cube root 9.
Found an element 4096 with square root 64 and cube root 16.
Did not find an element that is both a perfect square and a perfect cube.
Effectuer des calculs sur des tableaux
La Array.average fonction retourne la moyenne de chaque élément d’un tableau. Il est limité aux types d’éléments qui prennent en charge la division exacte par un entier, qui inclut des types à virgule flottante, mais pas des types intégraux. La Array.averageBy fonction retourne la moyenne des résultats de l’appel d’une fonction sur chaque élément. Pour un tableau de type intégral, vous pouvez utiliser Array.averageBy et faire en sorte que la fonction convertit chaque élément en type à virgule flottante pour le calcul.
Utilisez ou Array.min obtenez Array.max l’élément maximal ou minimal, si le type d’élément le prend en charge. De même, Array.maxBy et Array.minBy permettre à une fonction d’être exécutée en premier, peut-être de transformer en un type qui prend en charge la comparaison.
Array.sum ajoute les éléments d’un tableau et Array.sumBy appelle une fonction sur chaque élément et ajoute les résultats ensemble.
Pour exécuter une fonction sur chaque élément d’un tableau sans stocker les valeurs de retour, utilisez Array.iter. Pour une fonction impliquant deux tableaux de longueur égale, utilisez Array.iter2. Si vous devez également conserver un tableau des résultats de la fonction, utilisez Array.map ou Array.map2, qui fonctionnent sur deux tableaux à la fois.
Les variations Array.iteri et Array.iteri2 permettent à l’index de l’élément d’être impliqué dans le calcul ; le même est vrai pour Array.mapi et Array.mapi2.
Les fonctions Array.fold, , Array.foldBack, Array.reduceBackArray.reduce, , Array.scanet Array.scanBack exécutent des algorithmes qui impliquent tous les éléments d’un tableau. De même, les variations Array.fold2 et Array.foldBack2 effectuent des calculs sur deux tableaux.
Ces fonctions pour effectuer des calculs correspondent aux fonctions du même nom dans le module Liste. Pour obtenir des exemples d’utilisation, consultez Listes.
Modifier des tableaux
Array.set définit un élément sur une valeur spécifiée.
Array.fill définit une plage d’éléments dans un tableau sur une valeur spécifiée. Le code suivant fournit un exemple de Array.fill.
let arrayFill1 = [| 1 .. 25 |]
Array.fill arrayFill1 2 20 0
printfn "%A" arrayFill1
La sortie est la suivante.
[|1; 2; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 23; 24; 25|]
Vous pouvez utiliser Array.blit pour copier une sous-section d’un tableau vers un autre tableau.
Convertir en et depuis d’autres types
Array.ofList crée un tableau à partir d’une liste.
Array.ofSeq crée un tableau à partir d’une séquence.
Array.toList et Array.toSeq convertir en ces autres types de collection à partir du type de tableau.
Trier les tableaux
Permet Array.sort de trier un tableau à l’aide de la fonction de comparaison générique. Permet Array.sortBy de spécifier une fonction qui génère une valeur, appelée clé, pour trier à l’aide de la fonction de comparaison générique sur la clé. Utilisez Array.sortWith si vous souhaitez fournir une fonction de comparaison personnalisée.
Array.sort, Array.sortByet Array.sortWith tous retournent le tableau trié en tant que nouveau tableau. Les variantes Array.sortInPlace, Array.sortInPlaceByet Array.sortInPlaceWith modifient le tableau existant au lieu de retourner un nouveau tableau.
Tableaux et tuples
Les fonctions Array.zip et Array.unzip convertissent les tableaux de paires de tuples en tuples de tableaux et vice versa.
Array.zip3 et Array.unzip3 sont similaires, sauf qu’ils fonctionnent avec des tuples de trois éléments ou tuples de trois tableaux.
Calculs parallèles sur des tableaux
Le module Array.Parallel contient des fonctions permettant d’effectuer des calculs parallèles sur des tableaux. Ce module n’est pas disponible dans les applications qui ciblent les versions du .NET Framework antérieures à la version 4.