Tableaux (F#)

Les tableaux sont des collections 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 des valeurs consécutives entre [| et |], séparées par des points-virgules, comme illustré 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 point-virgule 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 génère une erreur, car 3,0 est un float, alors que 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 est 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 de 1 à 10.

let array3 = [| for i in 1 .. 10 -> i * i |]

Pour créer un tableau dans lequel tous les éléments sont initialisés à zéro, utilisez Array.zeroCreate.

let arrayOfTenZeroes : int array = Array.zeroCreate 10

Accéder aux éléments

Vous pouvez accéder aux éléments du tableau à l’aide de crochets ([ et ]). La syntaxe à point d’origine (.[index]) est toujours prise en charge, mais n’est plus recommandée à partir de F# 6.0.

array1[0]

Les index des tableaux commencent à 0.

Vous pouvez également accéder aux éléments du tableau à l’aide de la notation de section, ce qui vous permet de spécifier une sous-plage du tableau. Voici des exemples de notation de section.

// 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 section est utilisée, une nouvelle copie du tableau est créée.

Types et modules de tableau

Le type de tous les tableaux F# est le type .NET Framework System.Array. Par conséquent, les tableaux F# prennent en charge toutes les fonctionnalités disponibles dans System.Array.

Le module Array prend en charge les opérations sur des tableaux unidimensionnels. Les modules Array2D, Array3D et 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 de System.Array.

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 avoir besoin d’un 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 les 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 qui sont 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, pas l’objet sous-jacent. L'exemple de code suivant illustre ceci.

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, mais 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 type System.Text.StringBuilder affecte l’objet System.Text.StringBuilder sous-jacent, 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 montre 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 - 1, en 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 en un seul tableau. 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 canal (|>), 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 la suivante :

[|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 fonction Array2D.create, qui est également disponible pour les tableaux jusqu’à quatre dimensions. L’exemple de code suivant montre d’abord comment créer un tableau de tableaux qui contiennent les éléments souhaités, puis utilise Array2D.init pour générer le tableau à deux dimensions 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 de tableau est prise en charge pour les tableaux jusqu’au 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 en tant que <type>[,] (par exemple, int[,], double[,]), et le type d’un tableau tridimensionnel est écrit sous la forme <type>[,,], et ainsi de suite pour les tableaux de dimensions plus élevées.

Seul un sous-ensemble des fonctions disponibles pour les tableaux unidimensionnels est également disponible pour les tableaux multidimensionnels.

Découpage de tableaux et tableaux multidimensionnels

Dans un tableau à deux dimensions (une 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-séquences de la même dimension ou d’une 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 à l’élément et les méthodes GetSlice surchargées. Par exemple, le code suivant crée un type de matrice qui encapsule le tableau 2D F#, implémente une propriété Item pour assurer la prise en charge de l’indexation du tableau 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 dans 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 testent les éléments dans un ou deux tableaux, respectivement. Ces fonctions prennent une fonction de test et retournent true si un élément (ou une paire d’éléments pour Array.exists2) satisfait à la condition.

Le code suivant montre l’utilisation de Array.exists et Array.exists2. Dans ces exemples, de nouvelles fonctions sont créées en appliquant un seul des arguments, l’argument de fonction dans notre cas.

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 répond à une condition booléenne. La variante Array.forall2 fait de même en utilisant 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

Recherche dans les tableaux

Array.find prend une fonction booléenne et retourne le premier élément pour lequel la fonction retourne true, ou lève System.Collections.Generic.KeyNotFoundException si aucun élément remplissant la condition n’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 de Array.find lorsque vous ne savez pas si un élément correspondant se trouve dans le tableau. De même, Array.tryFindIndex est similaire à Array.findIndex, sauf que le type d’option est la valeur de retour. Si aucun élément n’est trouvé, l’option est None.

Le code suivant montre 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 illustre 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 fonction Array.average retourne la moyenne de chaque élément d’un tableau. Elle est limitée aux types d’éléments qui prennent en charge la division exacte par un entier, ce qui inclut les types à virgule flottante, mais pas les types intégraux. La fonction Array.averageBy 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 convertisse chaque élément en type à virgule flottante pour le calcul.

Utilisez Array.max ou Array.min pour obtenir l’élément maximal ou minimal, si le type d’élément le prend en charge. De même, Array.maxBy et Array.minBy permettent à une fonction à être exécutée en premier, peut-être pour transformer en un type qui prend en charge la comparaison.

Array.sum ajoute les éléments d’un tableau, Array.sumBy appelle une fonction sur chaque élément et additionne les résultats.

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 fonctionne 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 ; il en est de même pour Array.mapi et Array.mapi2.

Les fonctions Array.fold, Array.foldBack, Array.reduce, Array.reduceBack, Array.scan et Array.scanBack exécutent des algorithmes qui impliquent tous les éléments d’un tableau. De même, les variantes 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 List. 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 vers et à partir 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 convertissent en ces autres types de collection à partir du type de tableau.

Trier des tableaux

Utilisez Array.sort pour trier un tableau à l’aide de la fonction de comparaison générique. Utilisez Array.sortBy pour 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.sortBy et Array.sortWith retournent tous le tableau trié sous la forme d’un nouveau tableau. Les variantes Array.sortInPlace, Array.sortInPlaceBy et Array.sortInPlaceWith modifient le tableau existant au lieu d’en retourner un nouveau.

Tableaux et tuples

Les fonctions Array.zip et Array.unzip convertissent des 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 des 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.

Voir aussi