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.
Related
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
}
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);
I have a base class :
interface IBaseClass{
int x;
int y;
baseClass someMethod();
}
and some derived class :
class dClass1 : IBaseClass {
int x;
int y;
baseClass someMethod();
}
class dClass2 : IBaseClass {
int x;
int y;
baseClass someMethod();
}
The value of property according to the subclass algorithm is different from other subclass
now i want cast these subclass to them:
dClass1 c1=new dClass1 ();
c1.x=4;
c1.y=5;
dClass2 c2=c1;//cast to dClass2 , but value of property set by according to the own algorithm
Console.WriteLine("{0}, {1}", c1.x, c1.y);//4,5
Console.WriteLine("{0}, {1}", c2.x, c2.y);//7,1
First off, lets make it clear that IBaseClass is not a base class, its an interface, which is something quite different. Pointing out the differences is not in the scope of this answer but you can easily read about it, starting here.
That said, as others have stated, you can't do what you want directly. Consider the canonical example IAnimal, Dog, Cat, etc. Evey dog and every cat are animals, but cats are not dogs and dogs are not cats and you are basically asking a cat to be a dog; you first need to teach cats how to dogify (they won't do that out of the box for you).
In order to achieve this behavior there are quite a few ways how you can do it:
User defined cast: You can define operators that convert from one class to another. If you make them implicit you'd even get your code to compile as it is right now:
public static implicit operator dClass2(dClass1 obj)
{ //logic to convert obj to corresponding new dClass2 instance }
Now this would be legal:
var c1 = new dClass1();
dClass2 c2 = c1; // implicit cast operator is called.
Note that if you were to implement the cast operator as explicit, the former code would not compile. You would need to explicitly cast c1:
var c2 = (dClass2)c1;
Define a dClass2 constructor that takes a dClass1 argument:
public dClass2(dClass1 obj) { ... }
and you'd write the following code:
var c1 = new dClass1();
var c2 = new dClass2(c1);
Define a static factory method in dClass2 that takes a dClass1 argument and produces a new dClass2 instance:
public static dClass2 CreateFrom(dClass1 obj) { ... }
And the corresponding code:
var c1 = new dClass1();
var c2 = dClass2.CreateFrom(c1);
Many more I haven't bothered to think about...
Which one you choose is up to personal taste. I'd probably use the explicit cast, but there is nothing inherently wrong with any of the options available.
dClass1 and dClass2 are two different types. You can't directly cast one to the other. You'd have to convert one to the other. For example:
dClass1 c1 = new dClass1
{
x=4,
y=5
};
dClass2 c2 = new dClass2
{
x = c1.x,
y = c1.y
};
Or, using multiple lines like your original code:
dClass1 c1 = new dClass1();
c1.x=4;
c1.y=5;
dClass2 c2 = new dClass2();
c2.x = c1.x;
c2.y = c1.y;
The point is, the system has no way to directly cast one type to another type. You can encapsulate this conversion into factory methods on either type, or on separate classes. But casting isn't an option. Just because the two types have members of the same type/name/etc. doesn't make them the same type.
What you're trying to do isn't possible. You can cast an object to a less (or more in some cases) derived type, but you can't cast an object to another type unless you define a custom cast on the type.
You can read about defining custom casts here: https://msdn.microsoft.com/en-us/library/ms173105.aspx
Can someone please explain why this doesn't work?
MyClass myClass1 = new MyClass();
object obj = myClass1;
MyClass myClass2 = obj; <-- error
If obj "points" to the same block of memory of type MyClass, then why can I not "point" myClass2 to the same block of memory on the last line?
Thanks for any help.
The type of myClass2 is "MyClass". You can assign to it any value that is of a type that is, or derives from, MyClass. object is not and does not derive from MyClass, so you need a cast.
If it were able to do this implicitly, what would happen if you did it with an object that is not really a MyClass?
c# compiler only allows you to implicitly cast from derived class to base class, not the other way around. In your case, you need to explicitly cast from object to Myclass which is the derived class
Because object is a base class here.
If I have this:
class Square : Shape
{
}
class Circle : Shape
{
}
I can do
Shape c = new Circle();
Think about this semantically, a circle is a shape. I can store a circle as a shape.
But I can't do:
Circle c = new Shape();
Because a shape is NOT a circle, it could be a Square. Consider:
Shape sq = new Square();
Shape cr = new Circle();
According to how you see it, this should then work:
Circle x = cr;
But without a cast even this should work:
Circle x = sq;//this will blow up, sq is a square.
Therefore you need a cast. Similarly an object could be anything a Form, a Button or a MyClass. You need to cast it so the runtime will throw an exception if it isn't the correct type.
C# is a statically typed language. You indicated that obj is of type object. Because the language is statically typed, you can only expect the compiler to respect the explicit type that you've specified for obj and complain about the fact that you're trying to treat an object as if it were a MyClass.
MyClass myClass1 = new MyClass();
MyClass myClass2 = myClass1 ;
you can directly assign a class of type A to another class of Same type, but not an object with out type because complier doesn't know what type that object is so in that case you need a cast
MyClass myClass1 = new MyClass();
object obj = myClass1;
MyClass myClass2 = (MyClass)obj;
this will work because (MyClass)obj; is telling compiler that obj is of type MyClass
I've got a problem with inheritance and generics.
This is the code that illustrates my problem:
namespace TestApplication
{
public class MyClass<T>
{
private T field;
public MyClass(T field)
{
this.field = field;
}
}
public class MyIntClass : MyClass<int>
{
public MyIntClass(int field)
: base(field)
{
}
}
}
And when I try to do something like this:
MyClass<int> sth = new MyClass<int>(10);
MyIntClass intsth = (MyIntClass) sth;
I receive cast exception: Invalid cast exception. Unable to cast 'TestApplication.MyClass`1[System.Int32]' to 'TestApplication.MyIntClass'.
What is more I cannot create cast operator:
public static implicit operator MyIntClass(MyClass<int> myClass)
because: 'TestApplication.MyIntClass.implicit operator TestApplication.MyIntClass(TestApplication.MyClass)': user-defined conversions to or from a base class are not allowed
I need to create casts as described above. I don't know why I cannot cast from a type that is the base class. How can I solve this problem?
Thanks in advance.
Edit
Thanks for Your answers.
Now I see that i cannot convert from a base class to derived class and i see that it doesn't have anything to do with generics.
But why i cannot create user-defined conversions from a base class? I have a method that returns the base class. I am able to define a conversion method but creating a cast operator imho would be a better solution.
You can only cast from a base class to a derived class if the object is actually of type derived class. I mean, you can't cast an instance of base (MyClass<int>) to MyIntClass. You can, however cast it if it was actually of type MyIntClass stored as an MyClass<int> instance.
MyClass<int> foo = new MyIntClass();
MyIntClass bar = (MyIntClass)foo; // this works.
Assume:
class Base {
int x;
}
class Derived : Base {
int y;
}
Base foo = new Base();
Derived bar = (Derived)foo;
if it was allowed, what would the value of bar.y be?
In fact, converting from Derived to Base is not a conversion at all. It's just telling the compiler to let the variable of type Base to point to an object of type Derived. It is possible since derived has more or equal features than Base which is not the case in the other way around.
If you were able to create a conversion operator between base and derived classes, the C# compiler would be unable to distinguish it from the built in relationships defined for them. This is why you cannot create cast operators along inheritance hierarchies.
The other answers so far are correct, but I'd like to point out that your example has nothing to do with generics. It's the equivalent of:
using System;
class Base {}
class Child : Base {}
class Test
{
static void Main()
{
Base b = new Base();
// This will throw an exception
Child c = (Child) b;
}
}
In the comments you asked:
But why conversion from a base class is not allowed?
Simple - it would make no sense. Consider the example:
class BaseClass
{
public int x;
public BaseClass(int StartX)
{
this.x = StartX;
}
}
class ChildClass: BaseClass
{
public int Y;
public BaseClass(int StartX, StartY): base(StartX)
{
this.y = StartY;
}
}
class Program
{
public static void Main()
{
BaseClass B = new BaseClass(3);
ChildClass C = (ChildClass)B;
Console.WriteLine(C.y);
}
}
What do you suppose this program would output, assuming the cast worked? Even worse - imagine that BaseClass has two child classes - ChildClassA and ChildClassB. Do you want this to work?
ChildClassA A = new ChildClassA();
BaseClass bc = (BaseClass)A;
ChildClassB B = (ChildClassB)bc;
This would effectively allow to cast ChildClassA instances to ChildClassB - completely wrong.
As Mehrdad stated, you cannot downcast an object. Upcasting is implicit, therefore you cannot overwrite it.
As for the implicit operator, you can still create a constructor in the derived class which receives a parameter of type baseclass.
If you need to cast freely, define the variable as baseclass, but instantiate derived classes.
As has been said, you're trying to cast an object into a type that it doesn't derive from. Did you perhaps want to do this:
MyClass<int> sth = new MyIntClass(10);
MyIntClass intsth = (MyIntClass) sth;
Instead of creating an MyIntClass, try an alias:
using MyClass<int> = What.Ever.Namespace.MyIntClass;
This is now valid:
MyClass<int> foo = new MyClass<int>();
MyIntClass bar = (MyIntClass)foo;
Just understand that when doing the using alias, you have to qualify your namespace on the alias type name (What.Ever.Namespace).
Regarding your second question:
But why i cannot create user-defined conversions from a base class?
Well, suppose you have this scenario
class Base {
}
class Derived {
public static operator Derived(Base b) { ... }
}
and you tried to do this
Base x = new Derived();
Derived y = (Derived)x;
should the conversion be called? Of course not! The value inside x is actually of type Derived, so the cast is direct, without conversion. But if the value was not of type Derived, but a concrete Base, then the user-defined conversion has to happen because otherwise we'd have a compiler error. This all makes no sense; user-defined conversions are found in compile-time, and the type of the value of x is only known in runtime. Therefore, the compiler would not know what to do - call the user-defined conversion or simply cast the value...
Hope this makes a bit of sense to you.
Answering to your last edit.
This code does already compile, it only fails at runtime:
MyIntClass intsth = (MyIntClass) sth;
So, the following cast operator would be redundant if left explicit:
public static implicit operator MyIntClass(MyClass myClass)
So, the compiler should prevent you from adding that conversion. I think the error might be confusing, but I think it just forbids converting class B to class A if B is derived from A (the warning seemed to me to prevent any conversion to A, at first).
If the operator is made implicit, it is also dangerous, because a downcasting can always fail, so you have to:
show the compiler that you know that, by adding an explicit cast;
show the reader (which includes yourself, minutes later) that the operation might fail.
Assignment/conversion of a base class to a derived class makes sense if you consider assignment or conversion to be a value by value copy. What's confusing about c# for
newbies is the inconsistent way it does things:
'int' is a 'simple' type:
int i = 5; // <- this creates an int.
int j = i; // <- this creates another int and copies the value of i into j.
'Object' is not a simple type:
Object a; // <- this does not create a copy of 'Object', only a reference to one
Object b = new Object(); // <- this actually creates an Object
a = b; // <- this sets the reference to an object a to the reference to an object b.
// both of them reference the same Object. No values were copied.
If it were doing a copy of values then copying to base class to a derived class would
work. C# doesn't work like other languages.
I think that might be what's confusing you.