Το casting και η μετατροπή τύπων είναι διαφορετικοί τρόποι να αλλάξεις μια έκφραση από έναν τύπο δεδομένων σε έναν άλλο.
Η τεκμηρίωση της C# κατατάσσει τη μετατροπή τύπων ως τη χρήση του τελεστή as ή του τελεστή is. Το casting ορίζεται ως η χρήση του τελεστή cast.
Στη C#, πολύ συχνά, έξω από τον χώρο των αριθμητικών τιμών και των ιεραρχιών κλάσεων, θα χρειαστεί να κάνεις μια μετατροπή καλώντας κάποιο μέλος του τύπου «προς», όπως η Int32.Parse() που μετατρέπει μια συμβολοσειρά σε ακέραιο, ή καλώντας ένα μέλος του τύπου «από», π.χ. object.ToString(). Οι προγραμματιστές της JavaScript και άλλων δυναμικών γλωσσών θα πρέπει να το έχουν υπόψη.
Σημείωσε ότι υπάρχουν τελεστές άρρητης και ρητής μετατροπής (που συζητούνται στο operator-overloading) και μπορούν να προσφέρουν αρκετά αυθαίρετο casting στους δικούς σου τύπους.
Το σύστημα τύπων της C# είναι κάπως αυστηρότερο από αυτό της C ή της JavaScript και κατά συνέπεια οι πράξεις casting είναι πιο περιορισμένες. Το άρρητο casting πραγματοποιείται ανάμεσα σε δύο αριθμητικούς τύπους, αρκεί ο τύπος «προς» να μπορεί να διατηρήσει την κλίμακα και το πρόσημο της τιμής του τύπου «από». Πρόσεξε στην τεκμηρίωση την εξαίρεση για τη μετατροπή σε πραγματικούς αριθμούς, όπου μπορεί να χαθεί ακρίβεια.
Μια άρρητη μετατροπή δεν δηλώνεται με κάποια ειδική σύνταξη. Για παράδειγμα:
int myInt = 1729;
long myLong = myInt;
Δεν υπάρχει άρρητη μετατροπή μιας αριθμητικής (ή συμβολοσειράς) έκφρασης σε bool. Η Βιβλιοθήκη Βασικών Κλάσεων (BCL) παρέχει τη Convert.ToBoolean() για αυτόν τον σκοπό.
Μια έκφραση τύπου char μπορεί να μετατραπεί άρρητα σε int. Η μετατροπή στην αντίθετη κατεύθυνση πρέπει να είναι ρητή. Δεν είναι όλες οι τιμές του int έγκυροι χαρακτήρες utf 16.
Όπου οι αριθμητικοί τύποι δεν μπορούν να μετατραπούν άρρητα, μπορείς γενικά να χρησιμοποιήσεις τον τελεστή ρητής μετατροπής.
Όταν η τιμή που μετατρέπεται δεν μπορεί να αναπαρασταθεί από τον τύπο «προς», επειδή δεν είναι αρκετά ευρύς ή υπάρχει σύγκρουση προσήμου, τότε στην περίπτωση των ακεραίων μπορεί να πεταχτεί μια εξαίρεση υπερχείλισης, ή στην περίπτωση των float και double η μεταβλητή του τύπου «προς» μπορεί να πάρει την τιμή Infinity.
Μια έκφραση τύπου int μπορεί να μετατραπεί ρητά σε char. Αυτό μπορεί να οδηγήσει σε ένα μη έγκυρο char.
int largeInt = Int32.MaxValue;
int largeNegInt = Int32.MinValue;
ushort shortUnsignedInt = ushort.MaxValue;
float largeFloat = float.MaxValue;
float smallFloat = 17.29f;
// implicit cast
int from_ushort = shortUnsignedInt; // 65535
float from_int = largeInt; // -21474836E+09
int from_char = 'a'; // 96
// explicit cast
uint from_largeInt = (uint)largeInt; // 2147483647
uint from_neg = (uint) largeNegInt; // 2147483648 or OverflowException is thrown (if checked)
int from_smallFloat = (int) smallFloat; // 17
int from_largeFloat = (int) largeFloat; // -2147483648 or OverflowException is thrown (if checked)
char from_intc = (char) 32; // ' '
char from_invalid_int = (char) 0xdcbf; // invalid char - no exception thrown
// no cast available
int fromString = Int32.Parse("42"); // 42
string toString = largeInt.ToString(); // "2147483647"
int fromString_bad = Int32.Parse("forty two"); // FormatException is thrown
Δες αυτό το άρθρο για τη λέξη-κλειδί checked.
Οποιοσδήποτε τύπος μπορεί να μετατραπεί άρρητα στη βασική του κλάση ή διεπαφή.
IList<int> ll = new List<int>();
Ένας τελεστής cast μπορεί να χρησιμοποιηθεί για τη μετατροπή από μια βασική σε μια παράγωγη κλάση.
IList<int> ll = new List<int>();
List<int> l = (List<int>)ll;
Αν η μετατροπή αποτύχει επειδή ο τύπος της έκφρασης που μετατρέπεται δεν σχετίζεται με τον τύπο προς τον οποίο μετατρέπεται, πετιέται ένα στιγμιότυπο της InvalidCastException.
Μια πιο συνηθισμένη προσέγγιση σε αυτές τις μετατροπές τύπων είναι να χρησιμοποιήσεις τη λέξη-κλειδί is:
interface IFoo { int Bar(); }
class Foo : IFoo { public int Bar() { return 42; }}
Object r = new Random();
IFoo ifoo = new Foo();
Object o = new Foo();
int result = 1729;
if (ifoo is Foo foo)
{
result = foo.Bar();
}
// result == 42
result = 1729;
if (o is Foo foo2)
{
result = foo2.Bar();
}
// result == 42
result = 1729;
if (r is Foo foo3)
{
result = foo3.Bar();
}
// result == 1729
Η λέξη-κλειδί as επιτελεί παρόμοια λειτουργία με το is, π.χ. var foo = ifoo as Foo;. Σε αυτό το παράδειγμα, το foo θα είναι null αν το ifoo δεν είναι τύπου Foo, διαφορετικά το ifoo θα ανατεθεί σε αυτό.
Οι τύποι μπορούν να ορίσουν τους δικούς τους προσαρμοσμένους τελεστές cast, ρητούς και άρρητους.
Παραδείγματα ρητών και άρρητων μετατροπών στη BCL είναι οι μετατροπές από και προς τη δομή BigInteger και άλλους αριθμητικούς τύπους
typeof
Αν χρειάζεται να εντοπίσεις τον ακριβή τύπο ενός αντικειμένου, τότε το is μπορεί να είναι λίγο πολύ επιτρεπτικό, καθώς θα μετατρέψει ένα αντικείμενο σε μια κλάση ή σε κάποια από τις βασικές της κλάσεις. Σε αυτή την περίπτωση, η λύση είναι το typeof και η Object.GetType().
object o = new List<int>();
o is ICollection<int> // true
o.GetType() == typeof(ICollection<int>) // false
o is List<int> // true
o.GetType() == typeof(List<int>) // true