0Pricing
C# Academy · Lezione

Conversioni definite dall'utente

Aggiunga operatori di conversione impliciti ed espliciti.

Conversioni definite dall'utente è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 4 lezioni in totale.

Conversioni definite dall'utente

C# consente a un tipo di definire come convertirsi in un altro tipo o da un altro tipo usando gli operatori implicit ed explicit. Le conversioni implicite avvengono automaticamente, mentre quelle esplicite richiedono un cast.

Una conversione implicita

Usi implicit operator quando una conversione è sempre sicura e non comporta perdita di informazioni. Il compilatore la applica automaticamente ovunque sia previsto il tipo di destinazione.

using System;

public struct Celsius
{
    public double Degrees;
    public Celsius(double d) { Degrees = d; }

    // Always safe: a Celsius is just a number
    public static implicit operator double(Celsius c) => c.Degrees;
}

public class Program
{
    public static void Main()
    {
        Celsius temp = new Celsius(21.5);
        double d = temp; // implicit, no cast needed
        Console.WriteLine(d);
    }
}

Una conversione esplicita

Usi explicit operator quando una conversione può comportare una perdita di informazioni o non riuscire. Chi effettua la chiamata deve scrivere un cast, indicando di accettare il rischio.

using System;

public struct Money
{
    public decimal Amount;
    public Money(decimal a) { Amount = a; }

    // Loses the fractional cents, so make it explicit
    public static explicit operator int(Money m) => (int)m.Amount;
}

public class Program
{
    public static void Main()
    {
        var m = new Money(19.99m);
        int dollars = (int)m; // explicit cast required
        Console.WriteLine(dollars);
    }
}

Convertire verso il proprio tipo

Le conversioni possono funzionare anche nell'altra direzione: da un altro tipo verso il proprio. In questo caso, un operatore implicit crea un Celsius a partire da un double grezzo.

using System;

public struct Celsius
{
    public double Degrees;
    public Celsius(double d) { Degrees = d; }

    public static implicit operator Celsius(double d) => new Celsius(d);

    public override string ToString() => Degrees + "C";
}

public class Program
{
    public static void Main()
    {
        Celsius t = 18.0; // double implicitly becomes Celsius
        Console.WriteLine(t);
    }
}

Implicita o esplicita: quale scegliere

La regola pratica è questa: renda la conversione implicita solo se non comporta mai perdita di dati e non genera mai eccezioni. Se può causare perdita di precisione, overflow o fallire, la renda esplicita.

using System;

public struct Percentage
{
    public double Value; // 0..1
    public Percentage(double v) { Value = v; }

    // Safe and lossless -> implicit
    public static implicit operator double(Percentage p) => p.Value;
    // Could be out of range -> explicit
    public static explicit operator Percentage(double v) => new Percentage(v);
}

public class Program
{
    public static void Main()
    {
        double d = new Percentage(0.25);
        var p = (Percentage)0.5;
        Console.WriteLine(d + " " + p.Value);
    }
}

Conversioni tra tipi personalizzati

Le conversioni non riguardano solo i tipi incorporati. Può convertire due tipi definiti da Lei, ad esempio da coordinate polari a coordinate cartesiane.

using System;

public struct Cartesian
{
    public double X, Y;
    public Cartesian(double x, double y) { X = x; Y = y; }
    public override string ToString() => "(" + Math.Round(X, 2) + ", " + Math.Round(Y, 2) + ")";
}

public struct Polar
{
    public double R, Theta;
    public Polar(double r, double theta) { R = r; Theta = theta; }
    public static explicit operator Cartesian(Polar p)
        => new Cartesian(p.R * Math.Cos(p.Theta), p.R * Math.Sin(p.Theta));
}

public class Program
{
    public static void Main()
    {
        var c = (Cartesian)new Polar(1.0, 0.0);
        Console.WriteLine(c);
    }
}

Le conversioni si combinano con gli operatori

Una volta definita una conversione, il valore può essere usato nelle espressioni del tipo di destinazione. Una conversione implicita in double consente di usare direttamente il tipo nelle operazioni aritmetiche.

using System;

public struct Meters
{
    public double Value;
    public Meters(double v) { Value = v; }
    public static implicit operator double(Meters m) => m.Value;
}

public class Program
{
    public static void Main()
    {
        var distance = new Meters(5);
        double doubled = distance * 2; // uses implicit conversion to double
        Console.WriteLine(doubled);
    }
}

Evitare conversioni implicite sorprendenti

Le conversioni implicite che non sono chiaramente sicure possono nascondere bug, perché il compilatore le applica in silenzio. In caso di dubbio, preferisca quella esplicita, così l'intento risulta visibile nel codice.

using System;

public struct UserId
{
    public int Value;
    public UserId(int v) { Value = v; }
    // Explicit on purpose: an int is not always a valid id
    public static explicit operator UserId(int v) => new UserId(v);
    public static explicit operator int(UserId id) => id.Value;
}

public class Program
{
    public static void Main()
    {
        var id = (UserId)42;
        int raw = (int)id;
        Console.WriteLine(raw);
    }
}

Gli operatori di conversione sono static

Come gli altri operatori, gli operatori di conversione sono public static. Esattamente uno dei tipi coinvolti deve essere il tipo che dichiara l'operatore.

using System;

public struct Fahrenheit
{
    public double Degrees;
    public Fahrenheit(double d) { Degrees = d; }
    public static implicit operator Fahrenheit(double d) => new Fahrenheit(d);
    public static implicit operator double(Fahrenheit f) => f.Degrees;
    public override string ToString() => Degrees + "F";
}

public class Program
{
    public static void Main()
    {
        Fahrenheit f = 98.6;
        double d = f;
        Console.WriteLine(f + " = " + d);
    }
}

Un tipo wrapper pratico

Le conversioni sono particolarmente utili per i tipi wrapper leggeri, che rafforzano il sistema dei tipi senza introdurre complicazioni. Qui un NonEmptyString viene convertito implicitamente in string, ma per crearlo è necessario un cast esplicito.

using System;

public struct NonEmptyString
{
    public string Value;
    public NonEmptyString(string v)
    {
        if (string.IsNullOrEmpty(v)) throw new ArgumentException("empty");
        Value = v;
    }
    public static explicit operator NonEmptyString(string s) => new NonEmptyString(s);
    public static implicit operator string(NonEmptyString s) => s.Value;
}

public class Program
{
    public static void Main()
    {
        var name = (NonEmptyString)"Ada";
        string s = name;
        Console.WriteLine(s);
    }
}

Provi Lei

Definisca un wrapper con una conversione implicita in uscita (sicura) e una esplicita in ingresso (convalidata). Noti quale direzione richiede un cast.

using System;

public struct Ratio
{
    public double Value;
    public Ratio(double v)
    {
        if (v < 0 || v > 1) throw new ArgumentOutOfRangeException(nameof(v));
        Value = v;
    }
    public static implicit operator double(Ratio r) => r.Value; // always safe
    public static explicit operator Ratio(double v) => new Ratio(v); // may throw
}

public class Program
{
    public static void Main()
    {
        var half = (Ratio)0.5;   // explicit, validated
        double d = half;          // implicit, safe
        Console.WriteLine(d * 100 + "%");
    }
}

Verifica rapida

Scelga il tipo di conversione corretto.

Riepilogo

Le conversioni definite dall'utente consentono ai Suoi tipi di interagire in modo chiaro.

  • implicit operator per conversioni sempre sicure e senza perdita di dati.
  • explicit operator quando si possono perdere dati o la conversione può fallire.
  • Le conversioni possono avere come destinazione tipi incorporati o personalizzati, in entrambe le direzioni.
  • Sono public static e vengono dichiarate da uno dei tipi coinvolti.

Domande Frequenti

La lezione «Conversioni definite dall'utente» è gratuita?

Sì — il testo completo di «Conversioni definite dall'utente» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 4 lezioni in totale.

Cosa imparerò in «Conversioni definite dall'utente»?

Aggiunga operatori di conversione impliciti ed espliciti. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare C# Academy?

Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «Conversioni definite dall'utente»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione C# Academy?

Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Overload degli operatori aritmetici
  2. Overload degli operatori di confronto
  3. Conversioni definite dall'utente
  4. Best practice per l'overload degli operatori
← Torna a C# Academy