Casting Problems with dreived classes - is there a general rule?

  • Thread starter Mac via DotNetMonster.com
  • Start date
M

Mac via DotNetMonster.com

Hi all,

I have a creating a my own tabpage class (MyTabPage) which inherits the .Net
TabPage class.

In the relevant event I want to loop through the collection of TabPages and
then when I find the TabPage I am after I want to cast this to MyTabPage so
that I can access the properties that I have added to this class.

When I try to do this I get an "invalid cast" error at runtime. Am I not able
to cast from a baseclass to a derived class? Is there a general rule of thumb?


regards,

Mac
 
B

Bjorn Abelli

...
I have a creating a my own tabpage class (MyTabPage) which
inherits the .Net TabPage class.

In the relevant event I want to loop through the
collection of TabPages and
then when I find the TabPage I am after I want to cast
this to MyTabPage so that I can access the properties
that I have added to this class.

When I try to do this I get an "invalid cast"
error at runtime. Am I not able to cast from
a baseclass to a derived class?

You cannot "cast" an object at all, what you can do is to change the type of
reference to it.

However, you can only change that type to anything the object really *is*
from the point you instantiated it.

Example:

MyTabPage x = new MyTabPage();

Now you have a reference of type 'MyTabPage' to the object.

TabPage y = (TabPage) x;

Now you have another reference to the same object, but of type 'TabPage'.

That is possible since any instance of 'MyTabPage' *is-a* 'TabPage', through
inheritance.

If you look on inheritance as an inheritance tree, the *lowest* you can cast
to is, the actual type you used at instantiation.

But you can also cast to any type that is higher in the tree in the same
line of heritage, e.g.

Panel z = (Panel) x;

You can also cast to (most) any interface type any of those classes has
inherited, e.g.

IComponent p = (IComponent) x;

Note, the instance itself couldn't care less, as it's *still* an instance of
'MyTabPage' in this case. It hasn't "become" an instance of another type,
but you now got a couple of *references* of other types to it.

So, the "solution" to your problem, is to simply instantiate those objects
*as* instances of 'MyTabPage' in the first place...

// Bjorn A
 
T

Truong Hong Thi

You can cast an object of type A to type B if the runtime type of the
object is B or a class derived from B. So in your case, you can cast
the tab page to MyTabPage if the tab page's runtime type is MyTabPage
or one of its subclasses. The question is: how did you use MyTabPage in
your app? Did the collection contain MyTabPage objects, or objects of
the .NET provided TabPage class?
 
M

Mac via DotNetMonster.com

Bjorn & Thi - thanks for your replies.

I managed to get around the error by not actually casting but drectly
assigning instance of MyTabPage = Current TabPage (in the collection).

But looking at the base tabpage definition I realised what you mentioned Thi -
the collection I loop through is a collection of TabPages not of MyTabPage.
So what I assume is happening even though I create a new MyTabPage and set
the properties, they are lost when I add it to a collection of TabPages.

Is there an easy way to create a collection in a TabControl that holds a
derived class of TabPage? The Add function for the TabPageCollection is not
overiddable so I assume this is not possible.

What I am actually trying to do is have a tabcontrol on a MDI container form
where each tabpage represents a open MDI form (I know sounds a bit crude -
but I am unsure how else to achieve this). The properties I am adding to
MyTabPage are to help uniquely identify each form.

Any other design ideas would be appreciated also.


regards,

Mac
 
T

Truong Hong Thi

Hi Mac,
I managed to get around the error by not actually casting but drectly
assigning instance of MyTabPage = Current TabPage (in the collection).
Isn't that raise a compile-time error?
But looking at the base tabpage definition I realised what you mentioned Thi -
the collection I loop through is a collection of TabPages not of MyTabPage.
So what I assume is happening even though I create a new MyTabPage and set
the properties, they are lost when I add it to a collection of TabPages.
No, nothing is lost. Maybe the VS.NET designer adds some tab pages for
you? And it add TabPage instead of MyTabPage.
If you only add instances of MyTabPage to your collection, it should
work.
Is there an easy way to create a collection in a TabControl that holds a
derived class of TabPage? The Add function for the TabPageCollection is not
overiddable so I assume this is not possible.
The Add function takes a param of type TabPage and that is good. You
don't need to override it. Just call TabPageCollection.Add(new
MyTabPage()). You might want to search your code, especially the code
generated by the VS.NET designer, to make sure there is no code similar
to TabPageCollection.Add(new TabPage()).

Regard,
Thi - http://thith.blogspot.com
 
B

Bjorn Abelli

...
So what I assume is happening even though I create
a new MyTabPage and set the properties, they are lost
when I add it to a collection of TabPages.

Nope, as I said, the instance itself is *still* a MyTabPage, but you can't
"reach" those properties unless you cast it to a *reference* of MyTabPage.

You could say that the "reference" can't allow you to do anything on a
specific reference than what the type of the reference is.
Is there an easy way to create a collection in a TabControl
that holds a derived class of TabPage?¨

You can add *any* instance from any derived class to it, as ther *are*
TabPages.
The Add function for the TabPageCollection is not
overiddable so I assume this is not possible.

And not necessary...

If you instantiated the TabPages as MyTabPages from the start, that wouldn't
be any problem, other than you need to "cast" it again when you fetch the
TabPages out of the Collection.

As I said, you *can* cast to references of a type that the instance really
*is*, and as a MyTabPage *is-a* TabPage, that wouldn't be any problem.

I think the problem here lies a tad in that you maybe rely to much on the
GUI editor?

If you add "ordinary" TabPages through the GUI editor, you can then go into
the source for InitializeComponent and simply change all...

new System.Windows.Forms.TabPage();

....to...

new MyTabPage();

And, as I said, when you want to actually make use of the special properties
you've added, you need to cast to such a reference. Example:

MyTabPage x = (MyTabPage) this.tabControl1.SelectedTab;

...and...

MyTabPage y = (MyTabPage) this.tabControl1.TabPages[2];

....is completely valid as long as the pages added to the collection *really*
are instances of MyTabPage.

Hope this helps.

// Bjorn A
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top