Why can't I implicitly cast this object to a class reference - c#

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

Related

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.

dynamically creating objects from string to derived types

What i'm tring to do is this.
I have a Inheritance tree that looks something like this
BaseType
BaseType : DerType1
BaseType : DerType2
BaseType : DerType3
so first i've declare a variable of type BaseType to be used
BaseType b;
Any of the derived types can be read in as a string
so i've got an instance creator something like
object o = Activator.CreateInstance(Type.GetType(readValue));
What i then want to do is assign this new object to B
Something like
b = o //Doesn't work obviously because of casting rules
b= (DerType1)o; //works
but i can't figure out how to dynamically retype the intended cast
b = (o.GetType())o; //what i want but can't be done like this
maybe there's a trick with using generics i'm not thinking about?
I found an article talking about doing it something like this with generics
public T GetInstance<T>(string type) where T: new()
{
return (T)Activator.CreateInstance(Type.GetType(typeName));
}
but it seems to me that i still will need to statically reference the type name in the call to this method
b = GetInstance<DerType1>("DerType1")
b = GetInstance<DerType2>("DerType2")
b = GetInstance<DerType3>("DerType3")
thanks for the ideas.
Maybe i should be taking a whole new, better approach?
Also maybe i'm just not paying attention as
b = (BaseType)Activator.CreateInstance(Type.GetType(typeName));
seems to be helpful
Don't cast to the derived types if you aren't doing anything with them. Just cast to BaseType:
BaseType b = (BaseType)Activator.CreateInstance(Type.GetType(readValue));
You only need to cast to a type more specific than BaseType if you are going to write code that relies on members of that derived type. If you are going to treat all derived types polymorphically, just cast to the base type.
Casts within a type hierarchy don't change the type of object you referencing ... they just perform a quick runtime check (to make sure the reference is really of that type) and then reinterpret the reference.
Why not just declare:
object o;
as
BaseType o;
Then you could do:
BaseType o = Activator.CreateInstance(Type.GetType(readValue)) as BaseType;
I would suggest creating a Factory for your types (and casting everything to the BaseType since that's the type you're really going to be using anyway):
public static BaseTypeFactory
{
public enum Types { DerType1, DerType2, DerType3 }
public static BaseType CreateInstance(Types type)
{
switch(type)
{
case Types.DerType1:
return (BaseType) Activator.
CreateInstance(Type.GetType("DerType1"));
case Types.DerType2:
return (BaseType) Activator.
CreateInstance(Type.GetType("DerType2"));
case Types.DerType3:
return (BaseType) Activator.
CreateInstance(Type.GetType("DerType3"));
default:
thrown new ArgumentException("Invalid Type specified");
}
}
}

Implicit typing of arrays that implement interfaces

I was under the impression that the C# compiler will implicitly type an array based off a type that they can all be implicitly converted to.
The compiler generates
No best type found for implicitly-typed array
public interface ISomething {}
public interface ISomething2 {}
public interface ISomething3 {}
public class Foo : ISomething { }
public class Bar : ISomething, ISomething2 { }
public class Car : ISomething, ISomething3 { }
void Main()
{
var obj1 = new Foo();
var obj2 = new Bar();
var obj3 = new Car();
var objects= new [] { obj1, obj2, obj3 };
}
I know that the way to correct this is to declare the type like:
new ISomething [] { obj1, ...}
But I'm after an under the covers type help here.
The C# compiler considers the set of types of all the specified elements. It does not consider common base types etc.
You could cast one of the expressions:
var objects= new [] { obj1, obj2, (ISomething) obj3 };
... but personally I'd just use the explicit form:
var objects= new ISomething[] { obj1, obj2, obj3 };
Alternatively, if you explicitly declared any or all of obj1, obj2 and obj3 as type ISomething, that would work fine too without changing the array initialization expression.
From the C# 3 spec, section 7.5.10.4:
An array creation expression of the
third form is referred to as an
implicitly typed array creation
expression. It is similar to the
second form, except that the element
type of the array is not explicitly
given, but determined as the best
common type (§7.4.2.13) of the set of
expressions in the array initializer.
Section 7.4.2.13 looks like this:
In some cases, a common type needs to
be inferred for a set of expressions.
In particular, the element types of
implicitly typed arrays and the return
types of anonymous functions with
block bodies are found in this way.
Intuitively, given a set of
expressions E1…Em this inference
should be equivalent to calling a
method
Tr M<X>(X x1 … X xm)
with the Ei as arguments. More
precisely, the inference starts out
with an unfixed type variable X.
Output type inferences are then made
from each Ei with type X. Finally, X
is fixed and the resulting type S is
the resulting common type for the
expressions.
If the instances can all be cast to the type of any one instance, than that type will be used. It's not enough for all instances to have any type in common, or else the implicity array initialization would always succeed and often generate undesired new object[] arrays.
As a slight addition to the Skeet's reply:
You can either cast one of the array items to the type you need (interface in this case) or if you had just a single element of that type (not deriving but of a direct type). Such as
public static IWindsorInstaller[] MobileRestComponentInstallers
{
get
{
return new []
{
new RepositoryInstaller(),
new AppSettingsInstaller(),
// tens of other installers...
GetLoggerInstaller() // public IWindsorInstaller GetLoggerInstaller()...
};
}
}
this will work, but pls don't do that :) Just define the array type and change the new[] to new IWindsorinstaller[].
It's much more readable having the array type defined explicitly.
Do like this for Class object( UIViewController) initialization in var array:
var page1 = new Class1();
var page2 = new Class2();
var pages = new UIViewController[] { page1, page2 };
Note: here UIViewController can be any class

Casting between classes that share the same interface

I have two interfaces IHeaderRow, and IDetailRow
I then have an object that implements both RawRow:IHeaderRow, IDetailRow
I then need to cast it to HeaderRow which implements IHeaderRow.
But when I try, it ends up being null or giving an exception.
I can cast ObjectRawRow to either interface IHeaderRow, or IDetailRow
var ObjectIHeaderRow = ObjectRawRow as IHeaderRow;
var ObjectIDetailRow = ObjectRawRow as IDetailRow;
But I can not cast ObjectRawRow to HeaderRow , or ObjectIHeaderRow to HeaderRow.
It throws the error Cannot convert source type 'IA' to target type 'A'
I need to cast it into the actual class HeaderRow.
Thoughts?
EDIT:
Even though setting up an explicit cast took care of the issue I thought I'd provide an answer to the people wondering, WHY I was doing what I was.
In short, I'm sequentially processing a file. Line by line. I read the row into RawRow, and until I look at a few values, I don't actually know what type of row it is going to be. I then wanted to cast it to the proper type.
You can only implicitly cast objects to types they inherit from or implement - since RawRow doesn't derive from HeaderRow, it's not possible.
Depending on your requirements, you could overcome this by writing an explicit conversion operator, creating a HeaderRow constructor that accepts a RawRow as its prototype, or by modifying your code to operate on an IHeaderRow.
Why do you need to cast it to a HeaderRow in the first place? If IHeaderRow produced the api that a HeaderRow implements, than you should just be able to act on IHeaderRow "objects" using the defined methods.
The point of an interface is so that you can treat a grouping of different objects as a similar type. Not so that you can cast different objects between classes that are not linked by inheritance.
First, why do you need to do such a weird cast? There's probably another design for what you're trying to do.
Second, the reason you can't do the cast is because a RawRow isn't an HeaderRow. The only guarantee it makes is that it implements IHeaderRow. The problem is that it has a bunch of other stuff too, stuff that HeaderRow doesn't have. And vice versa - HeaderRow probably has a bunch of stuff that ObjectRawRow doesn't have.
Imagine your classes look like this:
interface IHeaderRow
{
string GetText();
}
class HeaderRow : IHeaderRow
{
public string GetText()
{
return "My Label";
}
public int GetFoo()
{
return 42;
}
}
class ObjectRawRow : IHeaderRow
{
public string GetText()
{
return "My Raw Label";
}
}
Now if you do this, you're ok:
ObjectRawRow row = new ObjectRawRow();
IHeaderRow header = row as IHeaderRow;
string label = header.GetText(); // fine, since GetText is guaranteed to exist
But try this on for size:
ObjectRawRow row = new ObjectRawRow();
HeaderRow header = row as HeaderRow;
int magic = header.GetFoo(); // BOOM! Method doesn't exist,
// because the object isn't really a HeaderRow under the covers.
// It's still really an ObjectRawRow. What do you do now? Crash hard is what.
And that's why you can't cast outside of the inheritance tree.
You cannot cast ObjectRawRow to HeaderRow unless one inherits from the other.
Interfaces have nothing to do with it.
Consider:
class Shape
interface IHasCorners
class Rectangle : IHasCorners, Shape
class Triangle : IHasCorners, Shape
Rectangle myRectangle = new Rectangle();
Triangle myTriangle = new Triangle();
//upcasts
Shape s = (Shape)myRectangle;
IHasCorners hc = (IHasCorners)myRectangle;
//downcasts
Rectangle r2 = (Rectangle)s;
r2 = (Rectangle)hc;
//upcasts
s = (Shape)myTriangle;
hc = (IHasCorners) myTriangle;
//these downcasts won't work
//the variables now reference a Triangle instance
Rectangle r3 = (Rectangle)s;
r3 = (Rectangle)hc;
You will not be able to make this cast unless there is an inheritance relationship between the types. If that is not possible then the best you can do is create an explicit conversion operator that allows you to cast one type as another type.
If you do create an explicit conversion you should understand that this will be slower than casting as you will be invoking an method that will do work as opposed to casting which only changes the reference type and doesn't change any of the memory on the heap.
Consider this example that doesn't compile:
class Example
{
static void Main()
{
Foo foo = new Foo();
Bar bar = (Bar)foo;
}
}
class Foo { }
class Bar { }
Since there is no inheritance relations between the types nor is there an explicit conversion from Foo to Bar this cannot compile.
But adding an explicit conversion allows it to compile:
class Example
{
static void Main()
{
Foo foo = new Foo();
Bar bar = (Bar)foo;
}
}
class Foo
{
public static explicit operator Bar(Foo foo)
{
return new Bar();
}
}
class Bar { }
You can only cast an instance to a particular class if the object is actually an instance of that class (or is derived from that class).
It is not possible to cast an instance of class A to completely unrelated class B (which is what you're trying to do), even if they implement the same interfaces.
You can use the explicit keyword to create methods that will be called when you try to cast from IA to A. The reason it doesn't work without you writing your own method is because the compiler doesn't know what to do with the values that aren't being provided.

C# - Problem with generics and inheritance

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.

Categories

Resources