কাস্টিং আর টাইপ কনভার্সন একটি এক্সপ্রেশনকে এক ডেটা টাইপ থেকে আরেকটিতে বদলে দেওয়ার ভিন্ন ভিন্ন উপায়।
C# ডকুমেন্টেশন-এ টাইপ কনভার্সনকে as অপারেটর বা is অপারেটর ব্যবহার হিসেবে শ্রেণীবদ্ধ করা হয়েছে। আর কাস্টিং বলতে কাস্ট অপারেটর ব্যবহার করাকে বোঝানো হয়।
C#-এ প্রায়ই, সংখ্যার মান আর ক্লাস হায়ারার্কির জগতের বাইরে, আপনাকে রূপান্তর করতে হয় "to" টাইপের কোনো সদস্য কল করে, যেমন Int32.Parse(), যা একটি স্ট্রিং-কে ইন্টিজারে বদলে দেয়, অথবা "from" টাইপের কোনো সদস্য কল করে, যেমন object.ToString()। Javascript আর অন্য ডাইনামিক ভাষার ডেভেলপারদের এ সম্পর্কে সচেতন থাকা দরকার।
খেয়াল রাখবেন, ইমপ্লিসিট ও এক্সপ্লিসিট কাস্ট অপারেটর (operator-overloading-এ আলোচনা করা হয়েছে) পাওয়া যায়, যেগুলো দিয়ে নিজের টাইপেও বেশ ইচ্ছেমতো কাস্টিং আনা যায়।
C#-এর টাইপ সিস্টেম C বা Javascript-এর চেয়ে কিছুটা কঠোর, আর তার ফলেই কাস্টিং অপারেশন আরও সীমাবদ্ধ। ইমপ্লিসিট কাস্টিং দুটি সংখ্যার টাইপের মধ্যে ঘটে, যদি "to" টাইপটি "from" টাইপের মানের স্কেল ও চিহ্ন ধরে রাখতে পারে। ডকুমেন্টেশনে বাস্তব সংখ্যায় রূপান্তরের ব্যতিক্রমটি লক্ষ্য করুন, যেখানে নির্ভুলতা হারিয়ে যেতে পারে।
ইমপ্লিসিট কাস্ট বোঝাতে কোনো বিশেষ সিনট্যাক্স থাকে না। যেমন:
int myInt = 1729;
long myLong = myInt;
সংখ্যার (বা স্ট্রিং) এক্সপ্রেশন থেকে bool-এ কোনো ইমপ্লিসিট কনভার্সন নেই। এই কাজের জন্য Base Class Library (BCL) Convert.ToBoolean() দেয়।
char টাইপের একটি এক্সপ্রেশন ইমপ্লিসিটভাবে int-এ কাস্ট করা যায়। উল্টো দিকের কাস্টটি এক্সপ্লিসিট হতে হবে। int-এর সব মান বৈধ utf 16 ক্যারেক্টার নয়।
যেখানে সংখ্যার টাইপগুলো ইমপ্লিসিটভাবে কাস্ট করা যায় না, সেখানে সাধারণত এক্সপ্লিসিট কাস্ট অপারেটর ব্যবহার করা যায়।
যখন যে মানটি কাস্ট করা হচ্ছে সেটি "to" টাইপ দিয়ে প্রকাশ করা যায় না, কারণ টাইপটি যথেষ্ট চওড়া নয় বা চিহ্নের সংঘর্ষ আছে, তখন ইন্টিজারের ক্ষেত্রে একটি ওভারফ্লো এক্সেপশন ছোঁড়া হতে পারে, আর ফ্লোট ও ডাবলের ক্ষেত্রে "to" টাইপের ভ্যারিয়েবলটি 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 অ্যাসাইন করা হবে।
টাইপগুলো নিজেদের কাস্টম এক্সপ্লিসিট ও ইমপ্লিসিট কাস্ট অপারেটর ডিফাইন করতে পারে।
BCL-এ এক্সপ্লিসিট আর ইমপ্লিসিট কাস্টের উদাহরণ হলো BigInteger স্ট্রাক্ট থেকে অন্য সংখ্যার টাইপে এবং সেগুলো থেকে 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