Why does Console show type B not A, even though a2 was assigned to new B()? I cannot understand exactly what happens in A a2 = new B().
class A { }
class B : A { }
...
A a1 = new A();
A a2 = new B();
Console.WriteLine(a2.GetType());
A variable is just something that points to an object. You can refer an object through a variable of any type that it inherits from (or any interface it implements) but that doesn't change the type of the object itself - this is one of the forms of polymorphism in C#.
Because you have created instance of class B not A and you are able to hold in variable of type A due to inheritance feature of OOP as you are inheriting your B class from A.
But the actual type of the a2 is B not A though it can be represent as A as well, but the GetType() reutrns the run-time type which is B.
You can have a look at this SO post too which explains what the GetType is expected to return for an object and what is typeof() and how we can use is for inheritance hierarchy checking.
Hope it helps.
Just because you refer to it through type A doesn't mean that the actual type suddenly changes to A, it's still a B object. You decided to create one with new B().
You should be aware of the difference between compile time type and runtime type. The compile time type is the type the compiler knows about in this case the type you have declared - A. The runtime type is the type of the object that happens to be referenced by the variable in this case B. Compile time (what the compiler knows about) and runtime (what happens when the program is actually run) is a very important distinction that applies to types, errors and even calculations.
Related
I am looking at C# code taken from MSDN documentation on casting.
In this code Animal is a base class and Giraffe is a derived class of Animal class.
Question: Will implicit and explicit casting on reference types create new Heap storage locations? For example, will variable a point to same Heap location that the variable g points to, OR a will point to a new location on Heap that gets created as a result of implicit casting, and what is the reasoning behind the answer?
My guess is NO because then there would be too much Heap memory being consumed by C# code that is doing implicit casting very often. But, I am not sure of the answer and it's reason.
Also, for the explicit casting in same code it seems g2 will point to same location as g and so no new Heap location gets created by successful explicit casting operation on reference types.
Casting operation C# code from MSDN
// Create a new derived type.
Giraffe g = new Giraffe();
// Implicit conversion to base type is safe.
Animal a = g;
// Explicit conversion is required to cast back
// to derived type. Note: This will compile but will
// throw an exception at run time if the right-side
// object is not in fact a Giraffe.
Giraffe g2 = (Giraffe) a;
Animal and Giraffe class C# code
class Animal
{
bool IsFourLegged
{
get;
set;
}
bool CanSpeak
{
get;
set;
}
}
class Giraffe : Animal
{
string Country
{
get;
set;
}
string StripeColor
{
get;
set;
}
}
No, it will not create a new managed object instance. It will just create a new reference (on the call stack, or maybe in a CPU register) to the same instance.
Of course I am talking about casts between two reference types (where one is a base class of the other, or where at least one is an interface type), called reference conversions by the C# spec. Other kinds of casts are different.
As pointed out in the comments, a user-defined conversion operator may also exist between two class types (only when neither is a base class of the other). Such a cast is not a reference conversion, of course, and a different instance (or null) is returned! Commenter's example:
string str = "Name";
XName name = str;
The last line creates a new object instance of type XName (or re-uses an existing XName instance it may have). In any case, an XName can never be the same instance as a string! This conversion could really do anything because it is really just a method call (as seen by the runtime), to the member public static implicit operator XName(string expandedName), actually named op_Implicit or similar within the CIL.
Short version: Object.ReferenceEquals will show that the cast does not create a new object, just another reference to the same object.
Update: I originally thought this might be possible by implementing an explicit conversion if you wanted to make it happen for some reason, but it is not -- the code won't compile. The error message is:
CS0553: User-defined conversion `Giraffe.explicit operator
Animal(Giraffe)' cannot convert to or from a base class
https://ideone.com/G1k7Q2
Also see https://stackoverflow.com/a/17459267/234954 which references the c# spec...
(In C# 5.0) It's a pretty simple yes/no question which I can't seem to find an explicit answer for which probably means I'm looking in the wrong place or using the wrong terms in searching for the answer.
If I create a derived class object, then I cast it to a base class and the original reference goes out of scope, does the reference held in the base class casting preserve the entire derived class object? I.E. can I later recast it as the derived class with the original object always still intact?
This is covered in the C# language specification, section 6.1.6 (implicit reference conversions):
Reference conversions, implicit or explicit, never change the referential identity of the object being converted. In other words, while a reference conversion may change the type of the reference, it never changes the type or value of the object being referred to.
(My emphasis)
Your question seems to be concerned that there may be something akin to Object Slicing happening - but that's not something that can happen in C#.
YES of course. If you cast to another type, you change only the view to the same object.
The answer is YES. A reference has an associated type but the type of the reference never influences the type of the instance the reference points to.
class A {}
class B : A {}
// Here we create an instance of B and assign it to a reference of
// type A (B is a subclass of A so this is correct). This doesn't
// change the type of B.
A a = new B();
Console.WriteLine(a.GetType()) // => prints B
// You can always assign to Object (doesn't change the type of the instance.
object o = a;
Console.WriteLine(o.GetType()) // => prints B
// And you can cast a reference to a different type, as long as they
// are compatible.
B b = (B)a;
Console.WriteLine(b.GetType()) // => prints B
It's a reference to the same object. The compile-time type of the expression which has a value of that reference is irrelevant. It's important to understand that there really is only one object - it's not like there's a base class object and then an associated derived class object.
That's why you can downcast as well:
string x = "hello";
object y = x;
string z = (string) y;
All three variables have the same value - they're all references to the same object. No information is lost. The reference itself is just "a way of getting to an object" - the variable determines which references are valid, and informs the compiler about which members can be accessed via that variable, but it doesn't change the value itself.
If I do:
IList<WSACLI_ComunicazionePersonale> Comunicazioni = (from XmlNode n in m_oNode.SelectNodes("m_Detail_Row")
select new WSACLI_ComunicazionePersonale(n)).ToList();
it works perfect, building my list of WSACLI_ComunicazionePersonale object!
But, if I do:
IList<WSACLI_ComunicazionePersonale> Comunicazioni = m_oNode.SelectNodes("m_Detail_Row").Cast<WSACLI_ComunicazionePersonale>().ToList();
the list is null. Seems that Cast() doesn't call the constructor?
Because casting does not create a new object - it just "re-types"* the existing object so you can use it in a different way. There's no construction involved.
You can treat a Cat as a generic Animal, but it does not create a "new" Cat. Plus, it's still a Cat - you're just interacting with it like it were a generic Animal.
The reverse may also be true - if someone gives you an Animal you could interact with is a such. You could try to interact it as if it were a Cat, but if it is really a Dog, you can't (legally) treat it as a Cat.
* By re-type I mean change the type you're considering the object to be - the underlying type of the object does not change.
You do not create a new object: the instance remains the same. Only the type of the variable that references your instance is modified.
Your second piece of code should read something like this if you want the same functionality as the first:
IList<WSACLI_ComunicazionePersonale> Comunicazioni = m_oNode
.SelectNodes("m_Detail_Row")
.Select(n=> new WSACLI_ComunicazionePersonale(n))
.ToList();
There is no cast because you cannot cast the node to your object. In your first example, you created a new instance and passed the node to the constructor.
Constructor is only invoked when a new instance of Object is created in .Net language, whereas Casting (Type Casting) is a a method of changing the existing type of a object to different Type
Type Casting (On Wikipedia)
In computer science, type conversion, typecasting, and coercion are
different ways of, implicitly or explicitly, changing an entity of one
data type into another. This is done to take advantage of certain
features of type hierarchies or type representations. One example
would be small integers, which can be stored in a compact format and
converted to a larger representation when used in arithmetic
computations. In object-oriented programming, type conversion allows
programs to treat objects of one type as one of their ancestor types
to simplify interacting with them.
Animal animal = new Cat();
Bulldog b = (Bulldog) animal; // if (animal is Bulldog), stat.type(animal) is Bulldog, else an exception
b = animal as Bulldog; // if (animal is Bulldog), b = (Bulldog) animal, else b = null
animal = null;
b = animal as Bulldog; // b == null
I need to create a heterogeneous List of objects (custom classes). My first thought was to create a List<ISomeMarkerInterface> but I quickly learned that this is not what I want. My next thought was List<dynamic> and this didn't seem to be a bad idea. However, I was doing some research and came across this article about boxing and unboxing and in the example, they're doing basically what I want using List<Object>.
Aside from the fact that dynamic will be evaluated at runtime and Object at compile-time, what is the difference between List<dynamic> and List<Object>? Aren't they essentially the same thing?
There are 3 "general" types (although not all are real types) in C#: object, var and dynamic.
Object
An actual type, like any other type, with one special rule: if a type doesn't inherit, it inherits from object. From this, it follows that all types inherit from object, directly or indirectly.
Emphasis: object is a type. An object can be of type object, and the type has its methods, like ToString(). Since everything inherits from object, everything can be upcast into object. When you assign an object to an object reference, you are doing upcasting just like when you assign an Elephant type object to an Animal reference where Elephant inherits from Animal.
SomeType x = new SomeType();
object obj = x;
obj.DoSomething();
obj is treated as being of type object at compile time, and will be of type object at runtime (which is logical, since it is an actual type - obj is declared as object so can only be of that type)
obj.DoSomething() will cause a compile-time error, as object does not have this method, regardless of whether SomeType has it.
Var
This is not an actual type, it is merely shorthand for "compiler, figure out the type for me based on the right side of the assignment".
SomeType x = new SomeType();
var obj = x;
obj.DoSomething();
obj is treated as being of type SomeType at compile time, and will be of type SomeType at runtime, just as if you had written "SomeType" instead of "var".
if SomeType has a method DoSomething(), this code will work
if SomeType doesn't have the method, the code will cause a compile-time error
Dynamic
This is a type that tells the compiler to disable compile-time type checking on the variable. An object is treated as having the type dynamic at compile-time and run-time.
SomeType x = new SomeType();
dynamic obj = x;
obj.DoSomething();
obj is of type dynamic at compile and run time
if SomeType has a method DoSomething(), this code will work
if SomeType doesn't have the method, the code will compile, but throw an exception at run-time
note that dynamic can cause exceptions very easily if used carelessly:
public void f(dynamic x)
{
x.DoSomething();
}
This will throw an exception if x is of a type that doesn't have the DoSomething method, but it will still be possible to call it and pass any object as the parameter without a compile-time error, causing an error that only shows itself at run-time, and possibly only in specific circumstances - a potential bug. So if you use dynamic in any kind of public interface of a class, you should always manually type-check at runtime using reflection, carefully deal with exceptions, or not do it in the first place.
Note: the object being referred to never changes its type, of course. While obj may be object, the x that it refers to is still SomeType.
The difference is that if you use object and you try to access some member of your object it will be a compile time error (because object doesn't have this member). In order to work you need to know what the type is and cast it.
With dynamic you can access any member - no compile time error. If the member doesn't exist at runtime it would be a runtime error. This is the way to go if you know that your heretogeneous objects all have the same member for example.
However if this is the case there is another more clear solution: You can define an interface, with this member and then make all your heretogeneous objects implement it and your list can be List<IYourInterface>.
Keep in mind that dynamic's performance might be slightly worse, because of the, well, dynamic type resolution.
I was wondering why some casts in C# are checked at compile-time whereas in other cases the responsibility is dumped on CLR. Like above both are incorrect but handled in a different way.
class Base { }
class Derived : Base { }
class Other { }
static void Main(string[] args)
{
Derived d = (Derived)new Base(); //Runtime InvalidCastException
Derived d = (Derived)new Other(); //Compile-time Cannot convert type...
}
While reading "C# in depth" I've found the information on this topic where autor says:
"If the compiler spots that it’s actually impossible for that cast to work, it’ll trigger a compilation error—and if it’s theoretically allowed but actually incorrect at execution time, the CLR will throw an exception."
Does 'theoretically' mean connected by inheritance hierarchy (some another affinity between objects ?) or it is compiler's internal business?
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.
If your variable is of Base type, is can be theoretically constructed by Derived constructor, thus being a variable of Derived type actually. At compile time, compiler does not bother itself with trying to figure out whether in each particular case such downcast (representing a variable of Base type as an entity of Derived type) is possible.
Your sample is simple - you create a new class and cast it right away. But what if you get Base from somewhere else, e.g., some method call? Compiler just cannot "guess" what your method is going to return and therefore throw on not throw an error.
When you cast Other, compiler sees that there is no possibility that Other is actually Derived and throws an exception.