Say we have
class A { protected string field1; }
class B : A { protected string field2; }
class C : B { protected string field3; }
void foo(A a) {}
void bar(B b) {}
void foobar(C c) {}
Now consider what instances of these objects *actually* will be inside your hardware. (We can safely ignore the fact that A extends object for the purpose of looking at why your attempted cast doesn't make sense.) First a word about references: A reference is what we might also call a "managed pointer": Like a pointer, it simply contains the address where the data is stored, but unlike a pointer, we cannot obtain this address and the memory manager can move stuff around and update pointers as needed without us knowing anything about it. Since string is a reference type, an instance of A is a word of memory (4 bytes on a 32-bit system) containing a reference to string data. An instance of B however is two words of data, containing two references, to field1 and field2 data. And C of course is three words, laid out in memory like an instance of B appended with the additional reference to field3 data. What you want to do is the equivalent of trying to use an instance of A and pass it to foobar, which takes a parameter of type C. Since an A is just the word for the field1 reference, foobar might access memory outside the bounds of the object and it could screw up other live objects (placed next to the instance of A in memory). So clearly the compiler shouldn't let you do that. If you wanted the compiler to just go ahead and create an instance of C for you when you make the cast, it wouldn't know what to do with field2 and field3. There is no way *in general* to know that the MotorBike class (descendant type) works just fine with only the data it inherited from the Vehicle class. If there were, we could just go like this:
AmazingWebSerive s = (AmazingWebService)(new object());
Sadly, this doesn't work. :) Instead, it's you as a programmer who may know this and provide a way to construct a B with only A data, or a C with only A data, and so on. Then you decide what the defaults should be for the data that doesn't exist in A.
class A { protected string field1; }
class B : A { protected string field2; }
class C : B
{
protected string field3;
public C(A a) { field1 = a.field1; }
}
Now if I have an A and I want to "use it as a C" I can simply go C c = new C(a); and work from there. BUT... if the reason you derived your own Tag class was be