when casting, receiving: System.InvalidCastException (Specified cast is not valid)

G

Gamma

I'm trying to inherit subclass from System.Diagnostics.Process, but
whenever I cast a "Process" object to it's subclass, I encounter an
exception "System.InvalidCastException" ("Specified cast is not
valid"). How do I fix it ?

using System.Diagnostics;
..
..
class NewProcess: Process
{
public override String ToString()
{
return this.ProcessName;
}
}
..
..
Process p, n;
p = new Process;
DoSomethingOnProcess (p);
n = (NewProcess) p; // throws System.InvalidCastException:
Specified cast is not valid
..
..
..
Thank you in advance, for any help.
 
B

Bruce Wood

Gamma said:
I'm trying to inherit subclass from System.Diagnostics.Process, but
whenever I cast a "Process" object to it's subclass, I encounter an
exception "System.InvalidCastException" ("Specified cast is not
valid"). How do I fix it ?

using System.Diagnostics;
.
.
class NewProcess: Process
{
public override String ToString()
{
return this.ProcessName;
}
}
.
.
Process p, n;
p = new Process;
DoSomethingOnProcess (p);
n = (NewProcess) p; // throws System.InvalidCastException:
Specified cast is not valid

Yes, it would throw an InvalidCastException. You cannot cast a base
class object to a derived class reference, only the other way around.
The object to which p refers is a Process, not a NewProcess. Besides,
the cast is useless because n is a reference to a Process, too.

Perhaps you misunderstand the difference between object (instance) type
and reference type, and perhaps also some things about how inheritance
works?

What do you think should be happening in the code you wrote? That will
help me explain it better.
 
S

sloan

What error you're getting is correct.

This should work..........and show the subtle difference.

Process p, n;
p = new NewProcess();
DoSomethingOnProcess (p);
n = (NewProcess) p;
 
G

Gamma

Thank you for your help.

1. What I want to do is this: I have an array of processes, and I want
to put them in a listbox. Since the listbox uses the "ToString" method
to display the process's name, and since the "ToString" method of the
Process's class (System.Diagnostics.Process) returns the class's name
besides the name of the process (which is redundant information), I
inherited a class NewProcess that overrides only the "ToString" method.

2. My roots are C++, and in C++, if I have a class that inherits from
another class and overrides a method, the correct way to use it is in
the following way (C++ code):

Process *p,*n;
p = new Process;
DoSomething(p);
n = (MyProcess*)p;

while trying to learn C#, I used that same technique, but obviously not
successfully. Therefore, what I want to understand is this: I have a
Process object (which is a given situation), and I want to
polymorphically use it as my derived class (to force it to treat it's
data the way I want it to).
 
M

Martin Z

No offense, but that is bad C++ - Unsafe use of the leaky "new"
operator, use of deprecated C-style typecasting, and you're using a
subclass as a decorator for an existing object. Subclasses are new
types whose objects happen to be useable in the place of their
superclass objects - not ways to override old behaviour of an old
object.

What you want to do (in C++ or C) is wrap the old objects in a new
object, or else change the called method to use your subclass. The
general guideline in a generic-supporting language (C# 2.0 or C++) is
that casting is a design smell.

Create a wrapper like


public class MyProcessWrapper
{
private Process _process;
public MyProcessWrapper(Process process)
{
this._process = process;
}

public Override string ToString()
{
return "My New ToString Crap";
}
}


and then use

myList.Add(MyProcessWrapper(oldProcess));

If you need to get the process back out of the wrapper, you can make
the field public or put it in a property or something (property if this
is production code, pubclic field if this is your own tinkering).
 
P

Peter Duniho

Gamma said:
Thank you for your help.

1. What I want to do is this: I have an array of processes, and I want
to put them in a listbox. Since the listbox uses the "ToString" method
to display the process's name, and since the "ToString" method of the
Process's class (System.Diagnostics.Process) returns the class's name
besides the name of the process (which is redundant information), I
inherited a class NewProcess that overrides only the "ToString" method.

Then you need to actually create instances of NewProcess, not instances of
Process. If you are not creating the instances of the Process yourself, you
will need to wrap them as Martin suggests, since you can't go back and
change something created as a Process into a NewProcess.

If you ARE creating the instances, then the change sloan offered will work
fine. In that case, you can ensure that the instance created is of the
derived class you've defined, rather than the base class, and the override
will work just fine.
2. My roots are C++, and in C++, if I have a class that inherits from
another class and overrides a method, the correct way to use it is in
the following way (C++ code):

Process *p,*n;
p = new Process;
DoSomething(p);
n = (MyProcess*)p;

while trying to learn C#, I used that same technique, but obviously not
successfully.

I agree with Martin. It's true that a C++ compiler will let you do this.
But that doesn't make it correct code (and if you did a C++ safe typecast
like that, it would fail), nor does it do what you seem to think it does.

A true "override" of behavior involves virtual functions in C++. Without a
virtual function, the behavior is defined only by the type the pointer is
currently treated as.

For example:

class A
{
public:
int Value { return 5; }
}

class B : public A
{
public:
int Value { return 10; }
}

If you have this code:

A *a1, *a2;
B *b1;
a1 = new A();
a2 = (B *)a1;
b1 = (B *)a1;

Then a1->Value() returns 5. a2->Value() *also* returns 5. The statement
b1->Value() returns 10, but only because you're calling the function
B::Value explicitly. It has nothing to do with the actual instance a1 and
if you cast b1 back to a pointer to an A, you are back to the call to
Value() returning 5.

If all you're inheriting the class for is to return a different value when
you explicitly call B::Value(), you might as well skip the inheritance and
just hard-code your constant instead where it would have been used.

More commonly, when one talks about an "override", they mean that the class
will retain the overridden behavior even when the class is only known to be
a parent class. For example:

class A
{
public:
virtual int Value { return 5; }
}

class B : public A
{
public:
virtual int Value { return 10; }
}

In this case, if you have this code:

A *a1;
B *b1;

a1 = new A();
b1 = (B *) a1;
b1 = new B();
a1 = (A *) b1;

After the first two lines have executed, a1->Value() would return 5, as
would b1->Value(). After the third line has executed, b1->Value() would
return 10, and after the fourth line executes, a1->Value() would also return
10.

In other words, in this second example the value returned depends not on the
type of the variable, but on the type used when creating the instance of the
class.

Note that in both examples, casting something created as an A to a pointer
to a B is *illegal*. It doesn't harm anything in this case (as in the
second line of code executed), because no attempt is made to access
something that was defined only in the B class. But if the B class included
some member variable or a virtual function, either of which didn't exist in
the A class, you would get an error trying to access that part of the B
class through a pointer caSt from an instance of an A class (the exact error
would vary...it could just be simply the wrong data, or the program could
crash, depending on what you tried to access and where the object was in
memory).

In other words, the code you posted is really dangerous, and doesn't at all
do what you want. It didn't work in C++ and it doesn't work in C#.
Thankfully, C# is better about protecting you, and thus generates the error
you're getting.
Therefore, what I want to understand is this: I have a
Process object (which is a given situation), and I want to
polymorphically use it as my derived class (to force it to treat it's
data the way I want it to).

You can't force something that's not already a NewProcess to act as if it is
a NewProcess.

Pete
 
G

Gamma

Thank you all for your explanations, they were focused and profound. I
understand now my mistakes, and that the correct way to do what I want
is indeed by a wrapper class.
 
P

Peter Duniho

Gamma said:
Thank you all for your explanations, they were focused and profound. I
understand now my mistakes, and that the correct way to do what I want
is indeed by a wrapper class.

You're welcome. I happy you found the various replies helpful!
 

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