Operatori di test dei tipi ed espressioni di cast: is, as, typeof e cast

Questi operatori ed espressioni eseguono il controllo del tipo o la conversione dei tipi. L'operatore is controlla se il tipo di runtime di un'espressione è compatibile con un determinato tipo. L'operatore as converte in modo esplicito un'espressione in un determinato tipo se il tipo di runtime è compatibile con tale tipo. Le espressioni di cast eseguono una conversione esplicita in un tipo di destinazione. L'operatore typeof ottiene l'istanza System.Type per un tipo.

Operatore is

L' operatore is controlla se il tipo di runtime del risultato di un'espressione è compatibile con un determinato tipo. L'operatore is verifica anche un risultato dell'espressione rispetto a un criterio.

L'espressione con l'operatore di test del tipo is ha il formato seguente:

E is T

in cui E è un'espressione che restituisce un valore e T è il nome di un tipo o un parametro di tipo. E non può essere un metodo anonimo o un'espressione lambda.

L'operatore is restituisce true quando un risultato di un'espressione è non null e le condizioni seguenti sono vere:

L'operatore is non considera le conversioni definite dall'utente.

L'esempio seguente dimostra che l'operatore is restituisce true se il tipo di runtime del risultato di un'espressione deriva da un determinato tipo, ovvero se esiste una conversione di riferimento tra i tipi:

public class Base { }

public class Derived : Base { }

public static class IsOperatorExample
{
    public static void Main()
    {
        object b = new Base();
        Console.WriteLine(b is Base);  // output: True
        Console.WriteLine(b is Derived);  // output: False

        object d = new Derived();
        Console.WriteLine(d is Base);  // output: True
        Console.WriteLine(d is Derived); // output: True
    }
}

L'esempio successivo mostra che l'operatore is prende in considerazione le conversioni boxing e unboxing ma non le conversioni numeriche:

int i = 27;
Console.WriteLine(i is System.IFormattable);  // output: True

object iBoxed = i;
Console.WriteLine(iBoxed is int);  // output: True
Console.WriteLine(iBoxed is long);  // output: False

Per informazioni sulle conversioni C#, vedere il capito Conversioni della specifica del linguaggio C#.

Test del tipo con criteri di ricerca

L'operatore is verifica anche un risultato dell'espressione rispetto a un criterio. Nell'esempio seguente viene illustrato come usare un modello di dichiarazione per controllare il tipo di runtime di un'espressione:

int i = 23;
object iBoxed = i;
int? jNullable = 7;
if (iBoxed is int a && jNullable is int b)
{
    Console.WriteLine(a + b);  // output 30
}

Per informazioni sui modelli supportati, vedere Modelli.

Operatore as

L'operatore as converte in modo esplicito il risultato di un'espressione in un tipo di valore nullable o di riferimento specificato. Se la conversione non è possibile, l'operatore as restituisce null. A differenza di un'espressione cast, l'operatore non genera mai un'eccezione as.

Un'espressione nel formato

E as T

in cui E è un'espressione che restituisce un valore e T è il nome di un tipo o un parametro di tipo, produce lo stesso risultato di

E is T ? (T)(E) : (T)null

con la differenza che E viene valutato una sola volta.

L'operatore as considera solo conversioni di riferimenti, nullable, boxing e unboxing. Non è possibile usare l'operatore as per eseguire una conversione definita dall'utente. A tale scopo, usare un'espressione cast.

Nell'esempio seguente viene illustrato l'uso dell'operatore as:

IEnumerable<int> numbers = new List<int>(){10, 20, 30};
IList<int> indexable = numbers as IList<int>;
if (indexable != null)
{
    Console.WriteLine(indexable[0] + indexable[indexable.Count - 1]);  // output: 40
}

Nota

Come mostrato nell'esempio precedente, è necessario confrontare il risultato dell'espressione as con null per verificare se la conversione riesce. È possibile usare l'operatore is sia per verificare se la conversione ha esito positivo sia, se ha esito positivo, per assegnarne il risultato a una nuova variabile.

Espressione cast

Un'espressione cast nel formato (T)E esegue una conversione esplicita del risultato dell'espressione E nel tipo T. Se non esiste alcuna conversione esplicita dal tipo E al tipo T, si verifica un errore in fase di compilazione. In fase di esecuzione, è possibile che una conversione esplicita non riesca e che un'espressione cast generi un'eccezione.

L'esempio seguente illustra conversioni esplicite numeriche e di riferimento:

double x = 1234.7;
int a = (int)x;
Console.WriteLine(a);   // output: 1234

int[] ints = [10, 20, 30];
IEnumerable<int> numbers = ints;
IList<int> list = (IList<int>)numbers;
Console.WriteLine(list.Count);  // output: 3
Console.WriteLine(list[1]);  // output: 20

Per informazioni sulle conversioni esplicite supportate, vedere la sezione Conversioni esplicite della specifica del linguaggio C#. Per informazioni su come definire una conversione personalizzata del tipo esplicito o implicito, vedere Operatori di conversione definiti dall'utente.

Altri utilizzi di ()

È possibile usare le parentesi anche per chiamare un metodo oppure richiamare un delegato.

Le parentesi possono essere usate anche per specificare l'ordine in cui valutare le operazioni in un'espressione. Per altre informazioni, vedere Operatori C#.

Operatore typeof

L'operatore typeof ottiene l'istanza System.Type per un tipo. L'argomento dell'operatore typeof deve essere il nome o il parametro di un tipo, come illustrato nell'esempio seguente:

void PrintType<T>() => Console.WriteLine(typeof(T));

Console.WriteLine(typeof(List<string>));
PrintType<int>();
PrintType<System.Int32>();
PrintType<Dictionary<int, char>>();
// Output:
// System.Collections.Generic.List`1[System.String]
// System.Int32
// System.Int32
// System.Collections.Generic.Dictionary`2[System.Int32,System.Char]

L'argomento non deve essere un tipo che richiede annotazioni di metadati. Gli esempi includono i tipi seguenti:

  • dynamic
  • string? (o qualsiasi tipo riferimento nullable)

Questi tipi non sono rappresentati direttamente nei metadati. I tipi includono attributi che descrivono il tipo sottostante. In entrambi i casi, è possibile usare il tipo sottostante. Anziché dynamic, è possibile usare object. Anziché string?, è possibile usare string.

È possibile usare l'operatore typeof anche con tipi generici non associati. Il nome di un tipo generico non associato deve contenere il numero appropriato di virgole, ovvero una in meno rispetto al numero di parametri del tipo. L'esempio seguente illustra l'uso dell'operatore typeof con un tipo generico non associato:

Console.WriteLine(typeof(Dictionary<,>));
// Output:
// System.Collections.Generic.Dictionary`2[TKey,TValue]

Un'espressione non può essere un argomento dell'operatore typeof. Per ottenere l'istanza System.Type per il tipo di runtime del risultato dell'espressione, usare il metodo Object.GetType.

Test del tipo con l'operatore typeof

Usare l'operatore typeof per controllare se il tipo di runtime del risultato dell'espressione corrisponde esattamente a un determinato tipo. L'esempio seguente illustra la differenza tra il controllo del tipo eseguito con l'operatore typeof e il controllo del tipo con l'operatore is:

public class Animal { }

public class Giraffe : Animal { }

public static class TypeOfExample
{
    public static void Main()
    {
        object b = new Giraffe();
        Console.WriteLine(b is Animal);  // output: True
        Console.WriteLine(b.GetType() == typeof(Animal));  // output: False

        Console.WriteLine(b is Giraffe);  // output: True
        Console.WriteLine(b.GetType() == typeof(Giraffe));  // output: True
    }
}

Overload degli operatori

Gli operatori is, as etypeof non possono essere sottoposti a overload.

Un tipo definito dall'utente non può eseguire l'overload dell'operatore (), ma può definire conversioni di tipi personalizzate che possano essere eseguite da un'espressione cast. Per altre informazioni, vedere Operatori di conversione definiti dall'utente.

Specifiche del linguaggio C#

Per altre informazioni, vedere le sezioni seguenti delle specifiche del linguaggio C#:

Vedi anche