«کست کردن» و «تبدیل نوع» دو روش متفاوت برای تغییر یک عبارت از یک نوع داده به نوع دیگر هستند.
مستندات C# تبدیل نوع را استفاده از عملگر as یا عملگر is دستهبندی میکند. کست کردن به عنوان استفاده از عملگر کست تعریف میشود.
در C#، بیرون از حوزهی مقادیر عددی و سلسلهمراتب کلاسها، بسیار پیش میآید که ناچار شوید تبدیلی انجام دهید؛ برای نمونه با فراخوانی عضوی از نوع «مقصد» مانند Int32.Parse() که یک رشته را به یک عدد صحیح تبدیل میکند، یا با فراخوانی عضوی از نوع «مبدأ»، مثلاً object.ToString(). کسانی که با Javascript و سایر زبانهای پویا کار میکنند باید به این نکته توجه داشته باشند.
توجه کنید که عملگرهای کست ضمنی و صریح (که در operator-overloading بحث شدهاند) در دسترس هستند و میتوانند کست کردن نسبتاً دلبخواه را برای انواع خودتان فراهم کنند.
سیستم نوع C# تا حدی سختگیرانهتر از سیستم نوع C یا Javascript است و در نتیجه، عملیات کست کردن محدودتر است. کست کردن ضمنی بین دو نوع عددی رخ میدهد، به شرطی که نوع «مقصد» بتواند مقیاس و علامت مقدار نوع «مبدأ» را حفظ کند. در مستندات به این استثنا توجه کنید که هنگام تبدیل به اعداد حقیقی ممکن است دقت از دست برود.
کست کردن ضمنی با هیچ نحوهی نگارش خاصی نشان داده نمیشود. برای مثال:
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>();
از عملگر کست میتوان برای تبدیل از یک کلاس پایه به یک کلاس مشتقشده استفاده کرد.
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;. در این مثال، اگر ifoo از نوع Foo نباشد، foo برابر با null خواهد بود؛ در غیر این صورت، مقدار ifoo به foo نسبت داده میشود.
انواع میتوانند عملگرهای کست صریح و ضمنی سفارشی خودشان را تعریف کنند.
نمونههایی از کستهای صریح و ضمنی در 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