Compile-Time and Runtime Casting C#

Compile-time and runtime casting c#

  • Upcasts can be checked at compile time - the type system guarantees that the cast succeeds.
  • Downcasts cannot (in general) be checked at compile time, so they are always checked at runtime.
  • Unrelated types cannot be cast to each other.

The compiler considers only the static types. The runtime checks the dynamic (runtime) type.
Looking at your examples:

Other x = new Other();
Derived d = (Derived)x;

The static type of x is Other. This is unrelated to Derived so the cast fails at compile time.

Base x = new Base();
Derived d = (Derived)x;

The static type of x is now Base. Something of type Base might have dynamic type Derived, so this is a downcast. In general the compiler can't know from the static type of x if it the runtime type is Base, Derived, of some other subclass of Base. So the decision of whether the cast is allowed is left to the runtime.

Not throwing error in compile time when casting base to derived class

There are 2 types of casts

  • once that clearly not allowed when classes have no common base and hence cast have no chance to succeed. I.e. 'string' to 'int'. Such casts are caught by compiler and cause errors.
  • casts that have chance to succeed - base to derived have reasonable chance to succeed. Compiler allows such casts.

I believe the reason why (B)new A() is allowed at compile time even if cast is guaranteed to fail is because (B)someObjectOfTypeA can succeed and new A() is definitely one of such "object of type A". Compile time detection likely would require additional infrastructure and was not found beneficial (as this cast immediately fails at runtime hence have low chance to be missed by even most basic testing of your code).

Does compile-time type still exist at runtime?

Is the compile-time type Animal being the type of the variable a on the stack?

Yes (although saying on the stack is unnecessary - whether it is on the stack or not is irrelevant).

Check the IL for the code at SharpLab:

using System;
using System.Reflection;

public class Animal{}

public class Dog: Animal {}

public class Program
{

public static void Main()
{
Animal a = new Dog();

ShowType(a);

MethodInfo mi = typeof(Program).GetMethod("Main");
MethodBody mb = mi.GetMethodBody();

foreach (LocalVariableInfo lvi in mb.LocalVariables)
{
Console.WriteLine("Local variable: {0}", lvi.LocalType);
}
}

public static void ShowType<T>(T o)
{
Console.WriteLine(typeof(T)); // Animal
Console.WriteLine(o.GetType()); // Dog
}
}

Note, in particular:

.locals init (
[0] class Animal a
)

which clearly shows that the type of the variable is Animal (which is no surprise, it will always be consistent with the code).

Note also that reflection (at runtime) outputs Animal (not Dog). So clearly the metadata of the method is storing the variable type.

Implicit conversion at compile time

A literal integer is a constant, it will never change. The compiler can therefore reason out at compile time if the implicit conversion is safe and if it is, its nice enough to do it for you.

Thats also the reason why byte i = 300; will fail at compile time.

The same can’t be said when the conversion is of a non constant value; a variable. There is no way the compiler can know what value i will be so the implicit conversion is unsafe and disallowed.

Concerning why this behavior seems off with floats and doubles (see comments): The reason is that there is a float literal in the language, so if you want a float literal, use a float literal. There is no byte or short literal so the compiler helps you out

Also, fitting a valid int into a byte implies no loss of data/precision; the bits are the same, you are simply truncating 0 bits on the high end. The same can't be said when you convert a double into a float. The representation of any given number as a single or double precision floating point number are radically different and there is an inherent loss of precision. It stands to reason that the language design decisions differ between both scenarios as they are different alltogether.

Why can’t down-casting be checked at compile time?

A compiler certainly could implement checks that would work in trivial cases like this. But doing so would be unlikely to help "real" code very much, since programmers rarely write such obviously wrong code.

To handle more complicated cases, a compiler would have to perform much more complicated analysis. This is harder for the compiler writer to do, and is also slower for your machine to run, and it still wouldn't be able to catch every possible bad cast. And again, because most code doesn't have easily-identifiable errors of this sort, it's not clear that the payoff would be worth the cost of writing the analysis.

Two drawbacks of more complicated static analysis are error messages and false positives. First, having a tool explain a problem in code is often an order of magnitude harder than having the tool merely check for the problem. Second, as checked-for problems turn from "bad thing X will definitely happen" to "bad thing Y might happen", it becomes much more likely that the tool will flag things that aren't ever a problem in practice.

There's an interesting essay written by a company, selling static analysis tools, that was spun off from academic research. One thing they discovered is that they often made fewer sales with more complicated analyses! A Few Billion Lines of Code Later: Using Static Analysis to Find Bugs in the Real World

C# how to cast object to runtime type?

TL;DR

You can't cast something to an unknown type specified at runtime. That would mean that within your code, you don't know what the object's properties or methods are unless you use even more reflection. In that case what would be the point of casting it?


Sometimes we deal with types that aren't known until runtime. But unless the type really doesn't matter at all, the object is useless unless we can cast it to some predetermined type that is specified in our code, not at runtime.

In this line of code:

var val = property.GetValue(obj); 

the declared type of val is inferred by the compiler. That type is object because that's the type that GetValue returns. The actual type of the object could be string, int, List<Foo>, whatever. But you've got a variable val of type object.

If you could do this:

var val = property.GetValue(obj) as runtimeType;    

Then what would the compile-time type of val be? How can it have any, since runTimeType is a runtime value? The object is useless unless you can call methods or inspect its properties. But you can't do that without knowing the type, unless you use more reflection. But if your're going to do that then there's no point in casting it.

Somewhere downstream from the code you've posted you'll presumably want to actually do something with the object that involves its methods or properties. That means knowing what type you think it is and casting it as that type. That would be a type specified in your code, not something determined at runtime.

For example:

var val = property.GetValue(obj); // I know this is a string
var myString = (string)val;
var findX = myString.IndexOf("X");

I think it's a string so I cast it as a string. (There could be additional checks in there.) Now that I've cast it, I've got a variable that's declared as type string, and I can use it as a string. (Unless it wasn't a string - then it will throw a runtime exception.)

That's the benefit of casting - it allows us to assign something to a strongly-typed variable with a type we specify and then use it accordingly. Casting to an unknown type wouldn't benefit us.


At the risk of adding confusion: Someone could say that generics represent types unspecified at runtime, but that's not exactly true. List<T> doesn't specify what T is, but if you create a List<T>, somehow, somewhere you're going to specify the type in your code. In the vast majority of normal scenarios we have to know something about the type of an object or else the object is useless to us.

Dynamic cast at runtime

No. You can't cast to any type that is unknown at compile time. However, c# does have a special keyword for declaring variables of a type that is unknown - it's dynamic.

You can think of it like a form of late binding - The actual type of the variable is determind at run time only.

When you declare a dynamic variable, c# compiler actually creates a variable of type object, but does not perform any type checking.

The dynamic type enables the operations in which it occurs to bypass compile-time type checking. Instead, these operations are resolved at run time.

...

Type dynamic behaves like type object in most circumstances. However, operations that contain expressions of type dynamic are not resolved or type checked by the compiler. The compiler packages together information about the operation, and that information is later used to evaluate the operation at run time. As part of the process, variables of type dynamic are compiled into variables of type object. Therefore, type dynamic exists only at compile time, not at run time.



Related Topics



Leave a reply



Submit