1

I've looked around for some time now and can't seem to find a direct answer to my question.


I am creating (as an exercise, self induced, not homework) a basic Cast<T> method, where an object is supplied and if the conversion is valid then T is returned. The initial method was incredibly straight forward. Simply perform implicit conversion and return the result.

internal T Cast<T>(object val) => (T)val;

My thinking here was that this would either work or it would throw an exception at runtime. Well, it does throw an exception at runtime, which I expect to happen due to attempting to cast string to int for example.

However, what I didn't expect, is for it to fail to cast int to double or vice-versa. I can do this when explicitly stating types:

int a = 0;
double b = 0;
a = (int)b;
b = (double)a;

All of that works fine and throws no exceptions and from my understanding this is by design for the same reason that char to string works. The types are similar in which only their ranges are different. Per MSDN:

int - -2,147,483,648 to 2,147,483,647

double - ±5.0 × 10^−324 to ±1.7 × 10^308

Thus casting from double to int caps the value to int.MaxValue or MinValue respectively. For example, the following code will print int.MinValue both times:

int a = int.MaxValue;
double b = double.MaxValue;
a = (int)b;
Console.WriteLine($"int: {a}");
b = (double)a;
Console.WriteLine($"double: {b});

This makes me curious, is there a reason why we can't cast from object to T when our object is of type int and our T is of type double or is this just a .NET shortfall?

Hazel へいぜる
  • 2,751
  • 1
  • 12
  • 44
  • [Boxing and Unboxing](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing) – Reza Aghaei Dec 28 '18 at 21:43
  • Not really an answer so I'll keep it to a comment, but you should do something like `public TOut Cast(TIn val) => (TOut)val;`. Prevents these issues and the needless boxing / casting to object – John Dec 28 '18 at 22:17
  • @John That won't compile. The compiler won't know if the conversion is valid, so it won't allow it. The only way to make it compile is to box the value (or not write such a method in the first place). – Servy Dec 28 '18 at 22:22
  • @Servy not sure how on earth I didn't think that, sorry. – John Dec 28 '18 at 22:35
  • @Servy The method is more of an exercise prior to writing a method with explicit casting later similar to `DataRow.Field(string)`. It turns out that `SqlDataReader` doesn't offer such a method, and my product lead is considering implementing an extension method that offers such functionality. I just wanted to understand more of it myself. – Hazel へいぜる Dec 28 '18 at 22:38
  • @Servy so that I ensure I understand; based on the answer in the other question, I have to perform type-checking and return explicit casts in order for something like this to work? – Hazel へいぜる Dec 28 '18 at 22:42
  • @PerpetualJ You need to unbox the value into a variable of the type it actually is, and then convert it into whatever you want it to be turned into, or use an operation that knows how to do that dynamically at runtime (which is going to be *very* expensive; you almost certainly don't want to do that in a situation like this). – Servy Dec 28 '18 at 22:46
  • You have to keep in mind those casts work differently. if you cast an int to a double to compiler is smart enough to understand you actually want to convert the value (this can be seen if you convert 2.5 to an int you'll get the value 2, so it actually changes) now the cast in your cast function does no conversion, it tells to look at the object val as if it where an object of type T which doesn't work since a double is not an int. Even though they both represent numbers they store data in different ways –  Dec 28 '18 at 23:14

0 Answers0