Pagina personale di:
Carlo Vecchio
appunti di C#, R, SQL Server, ASP.NET, algoritmi, numeri
Vai ai contenuti

C# - Conversioni

C#

Conversioni implicite ed esplicite

  • Una conversione è implicita se è possibile in tutte le circostanze. Nella conversione non c'è una perdita di informazione e in ogni caso non viene generata una eccezione.
  • Una conversione è esplicita se è possibile solo in alcune circostanze. Le regole per la conversione possono essere complicate. È necessario chiedere al compilatore di effettuare la conversione altrimenti segnala un errore in fase di compilazione.

Conversioni implicite
  • Per esempio la conversione tra 'char' e 'ushort' è implicita perché entrambe le variabili sono codificate in un range da 0 a 65535. Il compilatore non deve fare alcuno sforzo per convertire le variabili.
  • Esempio di conversione implicita:

   char carattere = 'A';
   
ushort carattereInAscii = 0;
   carattereInAscii = carattere;
   
Console.WriteLine("Carattere {0} - Carattere in ASCII {1}", carattere, carattereInAscii);
   
Console.ReadKey();

  • Tabella delle possibili conversioni implicite tra tipi numerici (il 'char' può essere considerato un tipo numerico come 'ushort'):
       - byte --> short, ushort, int, uint, long, ulong, float, double, decimal
       - sbyte --> short, int, long, float, double, decimal
       - short --> int, long, float, double, decimal
       - ushort --> int, uint, long, ulong, float, double, decimal
       - int --> long, float, double, decimal
       - uint --> long, ulong, float, double, decimal
       - long --> float, double, decimal
       - ulong --> float, double, decimal
       - float --> double
       - char --> ushort, int, uint, long, ulong, float, double, decimal

Conversioni esplicite: Cast
  • Se si prova a convertire una variabile 'int' in una 'short' (anche se siamo sicuri che la variabile è limitata ed è contenuta nel range da -32768 a 32767), il compilatore dà un errore e suggerisce di applicare un cast.
  • Esempio:

   int numeroInt = 32000;
   
short numeroShort = 0;
   numeroShort = numeroInt;  // --> Dà errore

  • È sufficiente modificare la terza riga così:

   numeroShort = (short) numeroInt;

  • Una volta impostato il cast, se la variabile da convertire eccede i limiti della variabile di destinazione, il compilatore potrà segnalare un errore in fase di esecuzione solo se il programmatore ha chiesto al compilatore di verificare gli overflow. Questo può essere fatto nelle opzioni: Proprietà del progetto --> Compila --> Avanzate --> Controlla overflow/underflow aritmetico (default è disabilitato).
  • Esempio:

   int numeroInt = 1000000;  
   
short numeroShort = 0;
   numeroShort = (
short) numeroInt;  // 1000000 non ci sta in un short, ma non dà errore
   
Console.WriteLine("Numero int {0} - Numero short {1}", numeroInt, numeroShort);
   
Console.ReadKey();

  • La conversione avviene e la variabile short assume un valore che a prima vista non è comprensibile (ma che è pienamente giustificato dal fatto che alcuni bit sono andati persi e dal fatto che i numeri sono codificati secondo la rappresentazione del 'complemento a 2').
  • Si può anche forzare una istruzione ad essere verificata o no tramite 'checked' ed 'unchecked'.
  • La conversione non genera un errore in fase di esecuzione anche chiedendo esplicitamente al compilatore la verifica del range della variabile (terza riga):

   numeroShort = unchecked((short) numeroInt);

  • La conversione invece genera un errore in fase di esecuzione chiedendo al compilatore la verifica del range della variabile (terza riga):

   numeroShort = checked((short) numeroInt);

  • Il cast non può essere utilizzato in tutte le circostanze; negli altri casi utilizzare il ConvertTo().

Conversioni esplicite: ConvertTo()
  • Esistono vari tipi di ConvertTo():
       - Convert.ToBoolean() --> bool
       - Convert.ToByte() --> byte
       - Convert.ToChar() --> char
       - Convert.ToDecimal() --> decimal
       - Convert.ToDouble() --> double
       - Convert.ToInt16() --> short
       - Convert.ToInt32() --> int
       - Convert.ToInt64() --> long
       - Convert.ToSByte() --> sbyte
       - Convert.ToSingle() --> float
       - Convert.ToString() --> string
       - Convert.ToUInt16() --> ushort
       - Convert.ToUInt32() --> uint
       - Convert.ToUInt64() --> ulong
  • Osservare che i nomi delle conversioni sono diversi dai tipi C#; questo è dovuto al fatto che i comandi sono del namespace .NET Framework System e non sono i tipi nativi C#. Queste conversioni sono sempre checked (e le parole chiave checked e unchecked sono ignorate).

Conversioni esplicite: Parse() e TryParse()
  • Per convertire una stringa in un numero (soprattutto in caso di input da parte dell'utente) sono molto utilizzate Parse() e TryParse().
  • La differenza tra i due metodi sta nel fatto che Parse restituisce una eccezione nel caso non riesca a fare la conversione, mentre TryParse() restituisce un valore boolean per informare se la conversione è riuscita oppure no.
  • Questi due metodi si applicano ai tipi numerici.
  • Esempio di utilizzo di Parse():

   int valore = int.Parse("010");   // La conversione è OK.
   
int valore = int.Parse("a10");   // La conversione dà errore.

  • Esempio di utilizzo di TryParse(), notare che è necessario definire una variabile che va passata al metodo TryParse(). Notare anche l'utilizzo di 'out' nel secondo argomento del TryParse() per indicare che 'valore' è restituito dal TryParse():

   // TryParse restituisce true.
   
int valore = 0;
   
if (int.TryParse("010", out valore))
       
MessageBox.Show("La conversione è OK, in valore c'è 10.");   // Messaggio mostrato.
   
else
       
MessageBox.Show("La conversione non è OK, in valore c'è ancora 0.");

   // TryParse restituisce false.
   
int valore = 0;
   
if (int.TryParse("a10", out valore))
       
MessageBox.Show("La conversione è OK, in valore c'è 10.");
   
else
       
MessageBox.Show("La conversione non è OK, in valore c'è ancora 0.");   // Messaggio mostrato.

Array di byte -> Stringa
  • Utilizzare la classe 'System.Text.Encoding'.
  • L'array di input è un array unicode (ogni carattere è formato da 2 byte).
  • Esempio 1:

   byte[] b = new byte[] { 1, 2, 3, 4, 5, 6 };
   string s = System.Text.Encoding.Unicode.GetString(b);

  • Esempio 2:

   string theString = Encoding.UTF8.GetString(theBytes);

Array di char -> Stringa
  • Utilizzare il costruttore delle stringhe.
  • Esempio:

   // Stringa generica da un array di char
   char[] c = new char[3];
   c[0] = 'A';
   c[1] = 'B';
   c[2] = 'C';
   string s = new string(c);  // "ABC"

   // Stringa con un carattere ripetuto n volte
   string s = new string('X', 10);  // "XXXXXXXXXX"

   // Stringa generica da una parte di un array di char
   char[] c = new char[6];
   c[0] = 'A';
   c[1] = 'B';
   c[2] = 'C';
   c[3] = 'D';
   c[4] = 'E';
   c[5] = 'F';
   string s = new string(c, 1, 2);  // "BC"


Array di char -> Array di byte
  • Utilizzare la classe Encoding.
  • Esempio:

   ASCIIEncoding encoding = new ASCIIEncoding();
   Byte[] buffer = encoding.GetBytes(arFinale);


ASCII -> Char
  • Basta fare il casting esplicito.
  • Esempio:

   char carattere = (char) 125;
   // restituisce il carattere ')'

  • Altro esempio:
   string s = "";
   for (int i = 65; i <= 90; i++)
       s = s + (char) i;
   MessageBox.Show(s);


ASCII -> Stringa
  • Esempio:

   string carattere = ((char) 125).ToString();


Char -> ASCII
  • Basta fare il casting esplicito.
  • Esempio:

   short ascii = (short) 'A';
   // restituisce 65


Stringa -> Array di byte
  • La classe 'System.Text.ASCIIEncoding' è limitata e non supporta i catatteri speciali. Meglio utilizzare la classe 'System.Text.UnicodeEncoding'.
  • Attenzione che ogni carattere è codificato con 2 byte.
  • Esempio 1:

   string test = "Prova";
   UnicodeEncoding enc1 = new UnicodeEncoding();
   Byte[] arInput = enc1.GetBytes(test);


  • Esempio 2:

   byte[] theBytes = Encoding.UTF8.GetBytes(theString);

Stringa -> Array di char
  • Utilizzare il metodo 'ToCharArray'.
  • Esempio:

   char[] c1 = str1.ToCharArray();

Stringa -> Char
  • Utilizzare la classe 'Convert'.
  • Esempio:

   char c = Convert.ToChar(Input.Substring(0, 1));

Stringa -> Numero/Data
  • Utilizzare il metodo TryParse() che restituisce True se riesce a fare la conversione. Il risultato della conversione è restituito per riferimento nel secondo parametro.
  • Il metodo si applica a tutti i tipi di variabili numerici: int, short, float, ...
  • Esempio:

   string s = "2";
   int number;
   bool res = int.TryParse(s, out number);  // res = True  number = 2

  • Utilizzare il metodo Parse() che restituisce il dato convertito o un errore se non riesce a fare la conversione.
  • Esempio:

   string s = "2.345";
   float number;
   number = float.Parse(s);  // number = 2.345

Integer -> Esadecimale
  • Utilizzare il metodo ToString() indicando la formattazione necessaria.
  • Esempio:

   int valore = 54321;
   string s = valore.ToString("x");    // s = "d431"
   string s = valore.ToString("X");    // s = "D431"
   string s = valore.ToString("x8");   // s = "0000d431"

   string s = valore.ToString("X8");   // s = "0000D431"


Little-endian / Big-endian -> Integer
  • I numeri interi che, per essere memorizzati, necessitano di un certo numeri di byte, utilizzano posizioni di memoria consecutive.
  • I byte sono memorizzati dalla prima posizione di memoria in due modi:
    • Dal byte meno significativo in poi.
    • Dal byte più signicativo in poi.
  • I due tipi di memorizzazione si chiamano rispettivamente:
    • Little-endian.
    • Big-endian.
  • Il nome deriva dalla 'fila indiana': i byte sono disposti in 'fila' dal più piccolo al più grande o viceversa.
  • Le seguenti due funzioni, convertono le rappresentazioni 'little-endian' e 'big-endian' in integer. Si ponga attenzione al fatto che si dà per assodato che la rappresentazione da convertire occupi uno spazio di 4 byte consecutivi.
  • Il primo argomento è un array di byte, il secondo è la prima posizione dell'array che contiene il numero da convertire.

   int GetBigEndianIntegerFromByteArray(byte[] data, int startIndex)
   {
       return (data[startIndex] << 24)
               | (data[startIndex + 1] << 16)
               | (data[startIndex + 2] << 8)
               | data[startIndex + 3];
   }

   int GetLittleEndianIntegerFromByteArray(byte[] data, int startIndex)
   {
       return (data[startIndex + 3] << 24)
               | (data[startIndex + 2] << 16)
               | (data[startIndex + 1] << 8)
               | data[startIndex];
   }



© 2020 Carlo Vecchio
Torna ai contenuti