Why:
int x = 3;
string y = x.toString();
^ works
and
int x = 3;
string y = (string)x;
^ doesnt works
curiosity brings me here ...
Because the first uses the method int.ToString to convert an int to it's string representation whereas the second tries to cast the int to string which doesn't work because it is actually not a string but an int.
Read:
Explicit conversions (casts): Explicit conversions require a cast operator. Casting is required when information might be lost in the conversion, or when the conversion might not succeed for other reasons.
String and Int32 are not related at all, so they cannot be casted to each other and already the compiler will throw an error. Sometimes the compiler compiles successfully but you get an InvalidCastException at runtime when the cast failed.
Read: Compile-time and runtime casting c#
Note that you can convert the int to string via ToString and you can convert a string to int via int.Parse(or int.TryParse):
int z = int.Parse("3");
ToString isn't type casting. It's a method, inherited from object and implemented in System.Int32, which converts the integer to a string representation.
An int isn't a string, so casting rightfully fails. The ToString method is where you put custom logic that typecasting doesn't have, for converting an instance to its string representation. You can (and often should) implement ToString yourself in your custom classes and structs - it's often useful to have a meaningful string representation.