Invalid Cast Exception but build works fine - c#

public class A
{
public void M1()
{
Console.Write("Print M1 of Class A");
}
}
public class B:A
{
public void M2()
{
Console.Write("Print M2 of Class B");
}
}
public class C : B
{
public void M3()
{
Console.Write("Print M3 of Class C");
}
}
In main method we create objects like:-
A objA = new B();
B objB = new C();
A a = new A();
C objC = (C)a; /* this line throws runtime error System.InvalidCastException: 'Unable to cast object of type 'A' to type 'C'.' but build works fine */
objA.M1();
objB.M1();
objB.M2();
objC.M1();
objC.M2();
objC.M3();
I could not cast C to A directly first. Hence tried creating object A then explicit casted it. The intellisense takes it as valid code and build is also fine but during console app execution it throws error "Unable to cast object of type 'A' to type 'C'."

It's true; you could cast a C to an A any time you want but the only time you can do it the other way round is if you've stored a C in a variable typed as A. The compiler lets you do this because C descends from A, so a variable of type A is capable of holding an instance of type C. Hence, you could have legitimately stored a C in an A and you're casting to get it back to being a C:
A reallyC = new C();
C gotBack = (C)reallyC;
The compiler doesn't look too hard at what you've done before; it wouldn't see code like this:
A reallyA = new A();
C willFail = (C)reallyA;
and say "hey; you've stored an A in reallyA, and it can't be cast to a C". It just sees you attempt to cast reallyA to a C and thinks "it could be a C, because a C is a B is an A, so they're related ok.. I trust the dev knows what they're doing and I'll permit it"

Well, a is of (base) type A and can't be cast to C since C is derived from A. The reverse is possible: an object c of derived class C can be cast to base class A:
C c = new C();
A objA = (A) c;
Often we can try to cast with a help of is:
if (a is C objC) {
// a can be cast to C, objC now holds the result of the cast
objC.M3();
}
else {
// the cast is impossible
}

Related

Accessing derived class variable through object of base class in C#

I have code as follows
Declare.cs
Class B { }
Class D1 : B { public var1 }
Class D2 : B {}
B Baseobject = new B();
if(baseobject is D1){ Console.print(B.var1) }
When I compile this scenario I always get compiler error that var1 is not accessible to B. If var1 always needs to be in D1 is there way to resolve this?
First of all, it won't compile because you need to cast. Why do you need to cast? Because your object reference is a type of B and knows nothing about D1 type and its methods and properties. You need to read a bit more about basic OOP principles
The object needs to be an instance of D1, so your example is a bit wrong.
You then need to cast your object to D1.
B baseObject = new D1();
Console.WriteLine(((D1)baseObject).var1);

Covariant and Contravariant Monadic Types ala Scala's List in C#

I'm new to c# but relatively experienced with scala, I'm trying to make a mimic of scala's list class (which is extended by Cons and the static class Nil). I was hoping to get the type behaviour it had as well, since .NET has supported covariance/contravariance since 4.0. Allow me to show what I mean:
Scala REPL:
class A
class B extends A
class C extends A
val x = new B() :: new B()
//this is type List[B]
val y = new C() :: new C()
//this is type List[C]
val z = new C() :: x
//This uses contravariance to figure out and infer that this is type List[A]!!!
In C# this will throw a compiler error because C and B are not the same type with ImmutableList.
There don't seem to be examples online and I'm still quite the novice with C# so I thought it would be wise to ask if C# could do this in any way before attempting blindingly (I am still trying but I'm also learning the rest of the language first as I go).
Thanks!
In C# this will throw a compiler error because C and B are not the
same type with ImmutableList.
In C#, classes are not co/contravariant, these are properties of Interfaces and Delegates used via the in and out keywords. Remember, in C#, a List<T> is a mutable list, and doesn't work like the immutable List[T] in Scala.
What you can do is declare the base type for the List<T>:
void Main()
{
var list = new List<A>();
list.Add(new B());
list.Add(new C());
}
class A { }
class B : A { }
class C : A { }
Same goes for using an interface for T, but you can't go further than that. This will not compile:
void Main()
{
var bs = new List<B>();
var cs = new List<C>();
var result = bs.Concat(cs);
}
For more on that, see Why isn't there generic variance for classes in C# 4.0?

Reference types Explicit Conversion in c#

As I'm new to C#, So trying to explore the things. I came up with an ambiguity here,
As per MSDN:- An explicit cast is required if you need to convert from a base type to a derived type for Reference Types
Here's the link.
So i tried an example program
interface I1
{
void FirstInterface();
}
class A
{
public void FirstInterface()
{
Console.WriteLine("FirstInterface Implemented in Class A");
}
}
class B : A
{
public void ClassBMethods()
{
Console.WriteLine("Class B methods");
}
}
Void Main()
{
A baseClass = new A();
B derivedClass = (B)baseClass; //Converting from base type to derived type
//B derivedClass = baseClass as B; -> null
}
But I'm getting Invalid Cast Exception when trying to do an explicit cast.Can anyone help me out to make this understand. I'm not sure what i misunderstood here.
The baseClass instance is not of type B. It is of type A. No amount of casting will make it a type B.
Try the following.
A baseClass = new B();
B derivedClass = (B)baseClass;
B otherDerivedClass = baseClass as B;
Notice the A baseClass = new B();
So think about it this way, a circle is always a shape, but a shape is not always a circle. With that in mind, the following makes sense:
Shape shape = new Circle();
Circle circle = (Circle)shape;
While the following does not:
Shape shape = new Shape();
Circle circle = (Circle)shape;
In the former, the shape was instantiated as a circle, so you can cast back and forth. In the latter, the shape was not ever a circle, so you can't cast to a circle.
That's because baseClass isn't of type B. Explicit casting would be more for something like this
A baseReference = new B();
B derivedReference = (B)baseReference;
Or to be safe you and use as instead which will return the default (null in the case of reference types) if the cast fails.
A a = new A();
A aRefOfB = new B();
B aAsB = a as B;
B aRefOfBAsB = aRefOfB as B;
In that case aAsB will be null and aRefOfBAsB will not.
But in general you should prefer a design that doesn't require you to do any explicit casts in the first place if possible.

Cannot access member of a class through object reference

The following code executes without error and prints "In some", which means that the statement
m[0].Invoke(o, args);
invokes the function some which is a member of the foo class, on object o and affects its public variable i. But when we uncomment the last line of the code and try to compile it, it produces an error. Why??
using System;
using System.Reflection;
class foo
{
public int i;
public foo(int ii = 0)
{
i = ii;
}
public void some(int ii)
{
i = ii;
Console.WriteLine("In some ");
}
}
class main
{
static public void Main()
{
foo f = new foo();
object o = new foo();
Type t = typeof(foo);
object[] args = new object[1];
args[0] = 9;
MethodInfo[] m = t.GetMethods();
m[0].Invoke(o, args);
//Console.WriteLine(o.i);
}
}
But when we uncomment the last line of the code and try to compile it, it produces an error. Why??
Because you've declared o as System.Object, which doesn't have a variable i defined on it as far as the compiler is concerned. You'd need to either cast it to the known type, or use reflection to retrieve this value.
For example:
// You can cast here, since you know the type
foo oAsFoo = o as foo;
Console.WriteLine(oAsFoo.i);
Alternatively, use reflection to get the value:
FieldInfo field = t.GetField("i");
Console.WriteLine(field.GetValue(o));
You need to cast the o too foo in order to execute it.
Console.WriteLine(((foo)o).i)
C# is a statically typed (typed safe) language and only allows type
safe operations and as there is no public member i of class
object therefore it is not allowed by the compiler.
o is of type object which can hold object of any type but instance of object can not access the attributes of assigned class object.
Type casting to its respective class make the public members accessible like this.
Console.WriteLine(((foo)o).i)

Why is this cast invalid when `x as Y` works fine?

I stumbled across this odd case yesterday, where t as D returns a non-null value, but (D)t causes a compiler error.
Since I was in a hurry I just used t as D and carried on, but I am curious about why the cast is invalid, as t really is a D. Can anyone shed some light on why the compiler doesn't like the cast?
class Program
{
public class B<T> where T : B<T> { }
public class D : B<D> { public void M() { Console.Out.WriteLine("D.M called."); } }
static void Main() { M(new D()); }
public static void M<T>(T t) where T : B<T>
{
// Works as expected: prints "D.M called."
var d = t as D;
if (d != null)
d.M();
// Compiler error: "Cannot cast expression of type 'T' to type 'D'."
// even though t really is a D!
if (t is D)
((D)t).M();
}
}
EDIT: Playing around, I think this is a clearer example. In both cases t is constrained to be a B and is maybe a D. But the case with the generic won't compile. Does the C# just ignore the generic constraint when determining if the cast is legal? Even if it does ignore it, t could still be a D; so why is this a compile time error instead of a runtime exception?
class Program2
{
public class B { }
public class D : B { public void M() { } }
static void Main()
{
M(new D());
}
public static void M(B t)
{
// Works fine!
if (t is D)
((D)t).M();
}
public static void M<T>(T t) where T : B
{
// Compile error!
if (t is D)
((D)t).M();
}
}
In your second example you can change
((D)t).M();
to
((D)((B)t)).M();
You can cast from B to D, but you can't necessarily cast from "something that is a B" to D. "Something that is a B" could be an A, for example, if A : B.
The compiler error comes about when you are potentially jumping from child to child in the hierarchy. You can cast up and down the hierarchy, but you can't cast across it.
((D)t).M(); // potentially across, if t is an A
((D)((B)t)).M(); // first up the hierarchy, then back down
Notice also that you might still get a runtime error with ((D)((B)t)).M(); if t is not actually a D. (your is check should prevent this though.)
(Also notice that in neither case is the compiler taking into account the if (t is D) check.)
A last example:
class Base { }
class A : Base { }
class C : Base { }
...
A a = new A();
C c1 = (C)a; // compiler error
C c2 = (C)((Base)a); // no compiler error, but a runtime error (and a resharper warning)
// the same is true for 'as'
C c3 = a as C; // compiler error
C c4 = (a as Base) as C; // no compiler error, but always evaluates to null (and a resharper warning)
Change it to
public static void M<T>(T t) where T : D
This is the appropriate restriction if you want to mandate that T has to be of type D.
It won't compile if your restriction defines T as D of T.
Ex: You can't cast List<int> to int or vice versa
Your template function have a constraint that requires T to be B<T>.
So, when your compiler tries to convert the object t of type T to D it can't do it. Because T is guranteed to be B<T>, but not D.
If you add a constraint to require that T is D, this will work. i.e. where T: B<T>, D or simply where T: D which also guarantees that T is B<T>, beacuse of the inheritance chain.
And the second part of the question: when you call t as D it's checked at runtime. And, at runtime, using polymorphism, it's verified that t can be converted to D type, and it's done without errors.
NOTE: by the way, this code is sooooo strange. Are you sure about what you're doing?

Categories

Resources