Konwersje definiowane przez użytkownika
Dodawaj niejawne i jawne operatory konwersji.
Konwersje definiowane przez użytkownika to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.
Konwersje zdefiniowane przez użytkownika
C# pozwala typowi definiować sposób konwersji do innego typu lub z innego typu za pomocą operatorów implicit i explicit. Konwersje niejawne odbywają się automatycznie, natomiast jawne wymagają rzutowania.
Konwersja niejawna
Należy użyć implicit operator, gdy konwersja jest zawsze bezpieczna i bezstratna. Kompilator zastosuje ją automatycznie wszędzie tam, gdzie oczekiwany jest typ docelowy.
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);
}
}Konwersja jawna
Należy użyć explicit operator, gdy konwersja może powodować utratę informacji lub zakończyć się niepowodzeniem. Wywołujący musi użyć rzutowania, sygnalizując w ten sposób akceptację ryzyka.
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);
}
}Konwersja do własnego typu
Konwersje mogą również działać w drugą stronę: z innego typu do własnego. W tym przykładzie operator implicit tworzy wartość Celsius z surowej wartości double.
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);
}
}Niejawna czy jawna: jak wybrać
Praktyczna zasada: konwersję należy oznaczyć jako niejawną tylko wtedy, gdy nigdy nie powoduje utraty danych ani nie zgłasza wyjątku. Jeśli może prowadzić do utraty precyzji, przepełnienia lub niepowodzenia, należy oznaczyć ją jako jawną.
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);
}
}Konwersje między typami własnymi
Konwersje nie ograniczają się do typów wbudowanych. Można konwertować między dwoma własnymi typami, na przykład ze współrzędnych biegunowych na kartezjańskie.
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);
}
}Konwersje współdziałają z operatorami
Po zdefiniowaniu konwersji wartość może być używana w wyrażeniach typu docelowego. Niejawna konwersja do double pozwala bezpośrednio używać danego typu w działaniach arytmetycznych.
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);
}
}Unikaj zaskakujących konwersji niejawnych
Konwersje niejawne, które nie są w oczywisty sposób bezpieczne, mogą ukrywać błędy, ponieważ kompilator stosuje je po cichu. W razie wątpliwości należy preferować konwersję jawną, aby intencja była widoczna w kodzie.
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);
}
}Operatory konwersji są statyczne
Podobnie jak inne operatory, operatory konwersji mają modyfikatory public static. Dokładnie jeden z uczestniczących typów musi być typem, który deklaruje operator.
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);
}
}Praktyczny typ opakowujący
Konwersje są szczególnie przydatne w przypadku cienkich typów opakowujących, które wzmacniają system typów bez utrudniania pracy. W tym przykładzie NonEmptyString konwertuje się niejawnie na string, ale jego utworzenie wymaga jawnego rzutowania.
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);
}
}Wypróbuj samodzielnie
Należy zdefiniować typ opakowujący z niejawną konwersją na zewnątrz (bezpieczną) i jawną konwersją do wewnątrz (z walidacją). Należy zwrócić uwagę, w którym kierunku potrzebne jest rzutowanie.
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 + "%");
}
}Szybkie sprawdzenie
Należy wybrać właściwy rodzaj konwersji.
Podsumowanie
Konwersje zdefiniowane przez użytkownika pozwalają typom współdziałać w przejrzysty sposób.
implicit operatorsłuży do zawsze bezpiecznych, bezstratnych konwersji.explicit operatornależy stosować, gdy dane mogą zostać utracone lub konwersja może się nie powieść.- Konwersje mogą prowadzić do typów wbudowanych lub własnych, w obu kierunkach.
- Mają modyfikatory
public statici są deklarowane przez jeden z uczestniczących typów.
Ucz się C# dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 93
- Lekcje
- 346
Często zadawane pytania
Czy lekcja „Konwersje definiowane przez użytkownika” jest bezpłatna?
Tak — pełny tekst „Konwersje definiowane przez użytkownika” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Konwersje definiowane przez użytkownika”?
Dodawaj niejawne i jawne operatory konwersji. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć C# Academy?
Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Konwersje definiowane przez użytkownika”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?
Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Przeciążanie operatorów arytmetycznych
- Przeciążanie operatorów porównania
- Konwersje definiowane przez użytkownika
- Dobre praktyki przeciążania operatorów