Types référence intégrés (Référence C#)

C# a un nombre de types référence intégrés. Ils ont des mots clés ou des opérateurs qui sont synonymes pour un type dans la bibliothèque .NET.

Type d’objet.

Le type object est un alias de System.Object dans .NET. Dans le système de type unifié de C#, tous les types (les types référence et valeur, prédéfinis ou définis par l’utilisateur) héritent directement ou indirectement du type System.Object. Vous pouvez assigner des valeurs de tout type aux variables de type object. Toute variable object peut être attribuée à sa valeur par défaut à l’aide du littéral null. Quand une variable d’un type valeur est convertie en type objet, elle est dite boxed. Quand une variable de type object est convertie en un type valeur, elle est dite unboxed. Pour plus d’informations, consultez Conversion boxing et unboxing.

Type de chaîne

Le type string représente une séquence de zéro, un ou plusieurs caractères Unicode. string est un alias de System.String dans .NET.

Bien que string soit un type référence, les opérateurs d’égalité== (!= et ) sont définis pour comparer les valeurs des objets string, pas les références. Cela permet de tester l’égalité de chaînes de façon plus intuitive. Par exemple :

string a = "hello";
string b = "h";
// Append to contents of 'b'
b += "ello";
Console.WriteLine(a == b);
Console.WriteLine(object.ReferenceEquals(a, b));

Cette opération affiche « True », puis « False », car le contenu des chaînes est équivalent, mais a et b ne font pas référence à la même instance de chaîne.

L’opérateur + concatène les chaînes :

string a = "good " + "morning";

Cela crée un objet String qui contient « good morning ».

Les chaînes sont immuables : il est impossible de changer le contenu d’un objet String après avoir créé l’objet, bien que la syntaxe semble indiquer le contraire. Par exemple, lorsque vous écrivez ce code, le compilateur crée en fait un nouvel objet String pour stocker la nouvelle séquence de caractères, et ce nouvel objet est attribué à b. La mémoire allouée pour b (quand elle contenait la chaîne « h ») est alors éligible pour le garbage collection.

string b = "h";
b += "ello";

L' [] opérateur peut être utilisé pour l’accès en lecture seule aux caractères individuels d’une chaîne. Les valeurs d’index valides commencent à 0 et doivent être inférieures à la longueur de la chaîne :

string str = "test";
char x = str[2];  // x = 's';

De la même façon, l' [] opérateur peut également être utilisé pour effectuer une itération au sein de chaque caractère dans une chaîne :

string str = "test";

for (int i = 0; i < str.Length; i++)
{
  Console.Write(str[i] + " ");
}
// Output: t e s t

Les littéraux de chaîne sont de type string et peuvent être écrits sous deux formes, entre guillemets et entre @. Les littéraux de chaîne entre guillemets sont placés entre guillemets doubles (") :

"good morning"  // a string literal

Les littéraux de chaîne peuvent contenir tout littéral de caractère. Les séquences d’échappement sont incluses. L’exemple suivant utilise la séquence d’échappement \\ pour la barre oblique inverse, \u0066 pour la lettre f et \n pour un saut de ligne.

string a = "\\\u0066\n F";
Console.WriteLine(a);
// Output:
// \f
//  F

Notes

Le code d’échappement \udddd (où dddd est un nombre à quatre chiffres) représente le caractère Unicode U+dddd. Les codes d’échappement Unicode à huit chiffres sont également reconnus : \Udddddddd.

Les littéraux de chaîne textuelle commencent par @ et sont placés entre guillemets doubles. Par exemple :

@"good morning"  // a string literal

L’avantage des chaînes textuelles est que les séquences d’échappement ne sont pas traitées, ce qui facilite l’écriture, par exemple, d’un nom de fichier complet Windows :

@"c:\Docs\Source\a.txt"  // rather than "c:\\Docs\\Source\\a.txt"

Pour inclure un guillemet double dans une chaîne @-quoted, doublez-le :

@"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.

Type de délégué

La déclaration d’un type délégué est semblable à une signature de méthode. Elle a une valeur de retour et un nombre quelconque de paramètres de type quelconque :

public delegate void MessageDelegate(string message);
public delegate int AnotherDelegate(MyType m, long num);

Dans .NET, les types System.Action et System.Func fournissent des définitions génériques pour de nombreux délégués courants. Vous n’avez probablement pas besoin de définir de nouveaux types de délégué personnalisés. À la place, vous pouvez créer des instanciations des types génériques fournis.

Un delegate est un type référence qui peut être utilisé pour encapsuler une méthode anonyme ou nommée. Les délégués sont comparables aux pointeurs fonction en C++, mais ils offrent l’avantage d’être sûrs et de type sécurisé. Pour les applications de délégués, consultez Délégués et Délégués génériques. Les délégués sont la base des événements. Un délégué peut être instancié en l’associant à une méthode nommée ou anonyme.

Le délégué doit être instancié avec une méthode ou une expression lambda qui a un type de retour compatible et des paramètres d’entrée. Pour plus d’informations sur le degré de variance autorisé dans la signature de méthode, consultez Variance dans les délégués. Pour une utilisation avec des méthodes anonymes, le délégué et le code à lui associer sont déclarés ensemble.

La combinaison de délégués et la suppression échoue avec une exception runtime lorsque les types délégués impliqués au moment de l’exécution sont différents en raison de la conversion de variante. L’exemple suivant illustre une situation qui échoue :

Action<string> stringAction = str => {};
Action<object> objectAction = obj => {};
  
// Valid due to implicit reference conversion of
// objectAction to Action<string>, but may fail
// at runtime.
Action<string> combination = stringAction + objectAction;

Vous pouvez créer un délégué avec le type d’exécution approprié en créant un nouvel objet délégué. L’exemple suivant montre comment cette solution de contournement peut être appliquée à l’exemple précédent.

Action<string> stringAction = str => {};
Action<object> objectAction = obj => {};
  
// Creates a new delegate instance with a runtime type of Action<string>.
Action<string> wrappedObjectAction = new Action<string>(objectAction);

// The two Action<string> delegate instances can now be combined.
Action<string> combination = stringAction + wrappedObjectAction;

À compter de C# 9, vous pouvez déclarer des pointeurs de fonctionqui utilisent une syntaxe similaire. Un pointeur fonction utilise l' calli instruction au lieu d’instancier un type délégué et d’appeler la Invoke méthode virtuelle.

Type dynamique

Le type dynamic indique que l’utilisation de la variable et des références à ses membres contourne la vérification du type au moment de la compilation. Au lieu de cela, ces opérations sont résolues au moment de l’exécution. Le type dynamic simplifie l’accès aux API COM telles que les API Office Automation, aux API dynamiques telles que les bibliothèques IronPython et au modèle DOM (Document Object Model) HTML.

Le type dynamic se comporte comme le type object dans la plupart des cas. En particulier, toute expression non null peut être convertie en type dynamic. Le type dynamic diffère de object en cela que les opérations qui contiennent des expressions de type dynamic ne sont pas résolues et leur type n’est pas vérifié par le compilateur. Le compilateur empaquète des informations sur l’opération, qui sont ensuite utilisées pour évaluer l’opération au moment de l’exécution. Dans le cadre du processus, les variables de type dynamic sont compilées dans des variables de type object. Ainsi, le type dynamic existe seulement au moment de la compilation, et non au moment de l’exécution.

L’exemple suivant compare une variable de type dynamic à une variable de type object. Pour vérifier le type de chaque variable au moment de la compilation, placez le pointeur de la souris sur dyn ou obj dans les instructions WriteLine. Copiez le code suivant dans un éditeur où IntelliSense est disponible. IntelliSense affiche dynamic pour dyn et object pour obj.

class Program
{
    static void Main(string[] args)
    {
        dynamic dyn = 1;
        object obj = 1;

        // Rest the mouse pointer over dyn and obj to see their
        // types at compile time.
        System.Console.WriteLine(dyn.GetType());
        System.Console.WriteLine(obj.GetType());
    }
}

Les instructions WriteLine affichent les types d’exécution de dyn et obj. À ce stade, tous deux ont le même type, entier. La sortie suivante est produite :

System.Int32
System.Int32

Pour voir la différence entre dyn et obj au moment de la compilation, ajoutez les deux lignes suivantes entre les déclarations et les instructions WriteLine de l’exemple précédent.

dyn = dyn + 3;
obj = obj + 3;

Une erreur du compilateur est signalée pour la tentative d’ajout d’un entier et un d’objet dans l’expression obj + 3. Toutefois, aucune erreur n’est signalée pour dyn + 3. L’expression qui contient dyn n’est pas vérifié au moment de la compilation, car le type de dyn est dynamic.

L’exemple suivant utilise dynamic dans plusieurs déclarations. La méthode Main compare également la vérification de type au moment de la compilation avec la vérification de type au moment de l’exécution.

using System;

namespace DynamicExamples
{
    class Program
    {
        static void Main(string[] args)
        {
            ExampleClass ec = new ExampleClass();
            Console.WriteLine(ec.exampleMethod(10));
            Console.WriteLine(ec.exampleMethod("value"));

            // The following line causes a compiler error because exampleMethod
            // takes only one argument.
            //Console.WriteLine(ec.exampleMethod(10, 4));

            dynamic dynamic_ec = new ExampleClass();
            Console.WriteLine(dynamic_ec.exampleMethod(10));

            // Because dynamic_ec is dynamic, the following call to exampleMethod
            // with two arguments does not produce an error at compile time.
            // However, it does cause a run-time error.
            //Console.WriteLine(dynamic_ec.exampleMethod(10, 4));
        }
    }

    class ExampleClass
    {
        static dynamic field;
        dynamic prop { get; set; }

        public dynamic exampleMethod(dynamic d)
        {
            dynamic local = "Local variable";
            int two = 2;

            if (d is int)
            {
                return local;
            }
            else
            {
                return two;
            }
        }
    }
}
// Results:
// Local variable
// 2
// Local variable

Voir aussi