Click here to Skip to main content
15,888,170 members
Please Sign up or sign in to vote.
4.75/5 (5 votes)
See more:
I know this is silly. As a junior, i need to understand this clearly.

Lets say I have class Person and another class Vehicle. Why can't I write as below:

Vehicle v;
Person p = (Person) v;

This throws run time error.

My Question is how does .net know these two classes are not related and cannot be type casted.
What is the criteria for Type casting?
Posted
Updated 21-Apr-14 11:47am
v4
Comments
Sergey Alexandrovich Kryukov 21-Apr-14 17:53pm    
Interesting deep question, especially for a beginner. I'm rushing to answer you, because I saw many bad answers on related topics from people who do not understand this matter well.
Your question one drawback: it makes limited sense when you don't show the definition of Person and Vehicle. Anyway, I voted 5 (in first place), consider I gave you a credit. :-)
—SA

The question is not silly at all; it is pretty deep and not trivial.

Very basically: the ability to It does know that because an executable image in the .NET assembly carries metadata:
http://msdn.microsoft.com/en-us/library/ms404430%28v=vs.110%29.aspx[^],
http://msdn.microsoft.com/en-us/library/xcd8txaw%28v=vs.110%29.aspx[^].

In-depth MSDN article on assignment compatibility: http://msdn.microsoft.com/en-us/library/ee207183.aspx[^].

Now, a non-trivial part of your situation is detecting of lack of assignment compatibility during runtime. In many cases, the assignment-incompatible types can be detected statically, during compilation. In this case, metadata is also involved, but it can be used immediately by a compiler. A couple of samples:
C#
class Vehicle { // note: nothing inherited, equivalent to " : System.Object"
   // anything here
}

class Person { // note: nothing inherited
   internal string SomeMember; // see explanation below
   // anything else here
}

Vehicle v;
Person p = (Person) v; // compiler will show an error here: there is no a chance to interpret is as valid assignment 

I hope you understand why it cannot work. Class Vehicle does not have a member SomeMember, but Person does have it. When code could interpret the object p of the actual runtime type Vehicle as the object of the type Person, it would give the access to non-existing member Vehicle.SomeMember. Note that even of you defined the same member in the clas Vehicle, it would be a different member with the same name, not the same as code>Person.SomeMember. The result of addressing to this non-existent member would be unpredictable.

The cases when such error cannot be detected at compilation are less trivial and are related to inheritance and the notions of compile-time types and runtime types. Let me show some example. I'll also introduce some dummy base type, to 1) show explicit inheritance, 2) to demonstrate two cases.
C#
abstract class Person { /* ... */ }
// non-abstract won't change the runtime behavior

enum LicenseClass { A, B, C, D, }
class Driver : Person { 
    internal LicenseClass { get; set; }
}

class Passenger: Person {
    // some members; who cares what are they for someone who does not even have a license? :-)
}

class Test { // no matter what
    internal static DoSomething(Person person) {
        Driver driver = (Driver)person; // will it throw the same exception?
    }
    internal static DoSomethingWithDynamicCheck(Person person) {
        Drive driver = person as Driver; // note operator "as", see below
        if (driver == null) return;
        // if you wrote
        // if (driver == null) throw new SomeException(driver);
        // if would behave nearly like the method DoSomething 
        //
        // use driver legitimately
    }
}

// when Test.DoSomething throws exception? Let's see:
Driver someDriver = new Driver();
Person someOtherPerson = new Driver();
Test.DoSomething(someDriver); // will work without exceptions
Test.DoSomething(someOtherPerson); // also will work without exceptions
Person someNonDriver = new Passenger();
Test.DoSomething(someNonDriver); // will throw exceptions

As you can see, statically, during runtime, the method Test.DoSomethong does not know if the runtime type is assignment-compatible with Driver or not; the compile-time type only says that it may me either Driver, Passenger or something else. This is validated only during runtime. How? My method Test.DoSomethingWithDynamicCheck shows the code behind this mechanism (approximately). Please see:
http://msdn.microsoft.com/en-us/library/cscsdfbt.aspx[^],
see also: http://msdn.microsoft.com/en-us/library/scekt9xw.aspx[^].

But how the "as" operator can work? Because of the metadata embedded in the compiled assembly. You could also do it directly using Reflection and the type System.Type. This is one of the relevant reflection methods: http://msdn.microsoft.com/en-us/library/vstudio/system.type.isassignablefrom[^].

In a nutshell, the assembly metadata is the collection of objects representing all of the assembly types rather then instances of those types. Each instance of System.Object describes all the properties of the type, all its members and their respective properties.

—SA
 
Share this answer
 
v3
Comments
Joezer BH 22-Apr-14 2:09am    
Definitely a 5!
Sergey Alexandrovich Kryukov 22-Apr-14 2:16am    
Thank you very much.
—SA
Member 10576805 22-Apr-14 12:41pm    
Like your detailed explanation

Sorry my example gives compile time exception. Here is the MSDN link which generate run time exception.
http://msdn.microsoft.com/en-us/library/ms173105.aspx
Sergey Alexandrovich Kryukov 22-Apr-14 13:27pm    
Very good, thank you.
Don't you think I answered you in full? So, will you first accept this answer formally (green "Accept" button)? Of course, your follow-up questions will be welcome.

The exception you show is the one I explained in my answer. It should be thrown in the cases I explained (not assignment-compatible; do you understand this concept?). What is the example you refer to? If this is the example in your question, it does not tell anything before you show the definitions of Vehicle and Person; I already mentioned that.

—SA
Member 10576805 23-Apr-14 10:57am    
Yes I got it.
Because it maintains a hierarchy of classes, and it knows that a Car is a Vehicle is a Machine is a Object, and that a Man is a Person is an Animal is an Object - and you can only cast up and down a 'branch', never from 'branch' to a different 'branch'.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 21-Apr-14 18:28pm    
What "it"? How? The question was "how". You did not answer it at all.
—SA
Member 10576805 22-Apr-14 12:41pm    
This is also part of the answer.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900