C# inheritance broken?

G

groups

Mark,

Yes, reinterpret_cast is indeed unsafe. But if there are no added
members, it works, as in CRect : RECT.

But this strays from what I'm hoping to accomplish.

How is it that serialization can magically create a Document object
through casting an "object" to "Document," but I'm not allowed to use
the same trick to create a MyDocument instead? The Serialization
classes don't know about Document while deserialization is occuring,
but it still lets you cast the return value of Deserialize into a
Document type. What is the trick they are using?

Tony
 
B

Bruce Wood

Mark,

Yes, reinterpret_cast is indeed unsafe. But if there are no added
members, it works, as in CRect : RECT.

But this strays from what I'm hoping to accomplish.

How is it that serialization can magically create a Document object
through casting an "object" to "Document," but I'm not allowed to use
the same trick to create a MyDocument instead?

Because .NET doesn't trust you. :)

One of the goals of .NET was to produce code that was immune to the
sort of run-time memory hacking that is rampant in C and C++. If the
runtime lets you play tricks like reinterpret_cast, then the code can't
be verifiably safe, can it?

As I said in my other post: different design goals. One goal of C++ was
to give the programmer total power to do whatever he wants, and the
compiler will trust him to get it right (by generating code no matter
what it might do at runtime). One goal of C# is to produce only code
that can be verified to not clobber memory / reinterpret memory
patterns as that which they are not / etc.

The two design goals are, obviously, incompatible.

If you want to do this sort of thing in C#, you have to use the
"unsafe" keyword to tell the compiler / runtime to lay off, but even
then I'm not sure of just how far you can go with that, because I've
never used it.
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,

| >> You build it of course ;-)
|
| Hmmm...I'm not sure how that would happen. I'm still stuck with the
| fact that the third-party component's Load method returns a Document,
| which can't be converted to type MyDocument, even in DocumentLoader.

You simply have a crappy component :)


Use other
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,


| > --
| > Ignacio Machin
| > machin AT laceupsolutions com
| >
| This isn't a C# issue. It is a dotNet issue as I have run into the same
| issue of inheriting a base class (in my case, VB 2005 and
StringCollection)
| and providing a method for the base class object to become the object at
the
| heart of the derived class.

Not at all, A base class cannot become a derived class, A derived class can
be treated as a base class without any problem.

Think about, what would hppen if the derived object add a new property,
clearly the base does not has it , so what can the compiler do in this
case??

| This is a design limitation in the framework

No, it's simply bad design of the base class, or trying to made a bad use of
the class.
 
B

Bruce Wood

"Ignacio Machin ( .NET/ C# MVP )" <machin TA laceupsolutions.com> wrote in
message





issue of inheriting a base class (in my case, VB 2005 and StringCollection)
and providing a method for the base class object to become the object at the
heart of the derived class. This is a design limitation in the framework
itself. From a business logic perspective, it should be doable.

For the record, no language that I know of lets you do this. C++ allows
you to pretend to do it via an unsafe cast, but you're not really
getting a derived object, just playing with a base class object as
though it were a derived object, which is fodder for disaster unless
you keep careful track of what you're doing.

You can't use a base class instance as though it were a derived class
instance because the latter may have more fields than the former, and
so the base class instance doesn't have enough space to store the state
of the derived class.

There _are_ various strategies for using a base class instance as a
model for creating a derived class. Most of them, however, require some
coding. There's no "automatic" way of copying state from one instance
to another, which might be a nice addition.
 
R

rossum

Here is some more relevant information that I've just learned:

The Document.Load static method relies on System.Runtime.Serialization
to create a new Document object. Formatter.Deserialize returns an
object that is a Document, and this Document object can't be cast to a
MyDocument. Deserialization can't occur in a constructor, because the
Document object already exists, and you can't replace "this" with the
new Document object.

So it would seem that the limitation is there because of the way
serialization works, not because of a bad design on the part of the
author of Document.

Tony

Taking a completely different tack, how easy would it be for you to
parse through the Serialized Document file and change it to whatever
the equivalent Serialized MyDocument file would look like?

Given that you are trying to upcast the derived class, which goes
against the design goals of C#, this might be an easier way to work
round your problem.

rossum
 
G

groups

No, it's simply bad design of the base class, or trying to made a bad use of
the class.

OK, please enlighten me. What would be the proper design of the base
class? I see no way to inherit from such a base class, regardless of
the base class design!

Tony
 
M

Michael D. Ober

Bruce Wood said:
For the record, no language that I know of lets you do this. C++ allows
you to pretend to do it via an unsafe cast, but you're not really
getting a derived object, just playing with a base class object as
though it were a derived object, which is fodder for disaster unless
you keep careful track of what you're doing.

You can't use a base class instance as though it were a derived class
instance because the latter may have more fields than the former, and
so the base class instance doesn't have enough space to store the state
of the derived class.

There _are_ various strategies for using a base class instance as a
model for creating a derived class. Most of them, however, require some
coding. There's no "automatic" way of copying state from one instance
to another, which might be a nice addition.
A generalized method of converting a base class into a derived class with
the knowledge that the derived class may still require some initialization
would definitely be useful, even if you had to do it via a constructor that
takes an object of the base class as it's argument. The missing syntax, in
vb is

mybase = objBaseClass

In C# I think it would be

base = objBaseClass

In either case, since this is occurring in a constructor in place of the
base.New() or mybase.New statement, the programmer knows he still has to
instantiate and initialize all other private and protected objects in the
derived class.

Mike Ober.
 
J

Jon Skeet [C# MVP]

OK, please enlighten me. What would be the proper design of the base
class? I see no way to inherit from such a base class, regardless of
the base class design!

Instead of having a static method which returns a Document, create an
*instance* method which loads data into an existing instance. That's
the way XmlDocumentLoad works, for example.
 
J

Jake Stevenson

What is wrong with this approach?

class MyDocument : Document
{
public void CopyFromDocument(Document Original)
{
foreach (System.Reflection.PropertyInfo Prop in
Original.GetType().GetProperties())
{
if (Prop.CanWrite)
{
Prop.SetValue(this, Prop.GetValue(Original, null),
null);
}
}
foreach (System.Reflection.FieldInfo Field in
Original.GetType().GetFields())
{
Field.SetValue(this, Field.GetValue(Original));
}
}
}

Something similar can be implemented in the base class and would be
inherited by your class. There may be a performance issue with
Reflection though.
 
B

Bruce Wood

A generalized method of converting a base class into a derived class with
the knowledge that the derived class may still require some initialization
would definitely be useful, even if you had to do it via a constructor that
takes an object of the base class as it's argument. The missing syntax, in
vb is

mybase = objBaseClass

In C# I think it would be

base = objBaseClass

In either case, since this is occurring in a constructor in place of the
base.New() or mybase.New statement, the programmer knows he still has to
instantiate and initialize all other private and protected objects in the
derived class.

Mike Ober.

Agreed. That would be nice. I wouldn't need it often, but it would get
one out of some tricky corners. My only point was that the whole "I
have a base class instance and I want to treat it as though it were a
derived class instance" is completely unsafe and therefore runs
against the grain of what .NET is supposed to be all about. Being able
to copy state, though, would be handy.
 
T

Tom Shelton

Agreed. That would be nice. I wouldn't need it often, but it would get
one out of some tricky corners. My only point was that the whole "I
have a base class instance and I want to treat it as though it were a
derived class instance" is completely unsafe and therefore runs
against the grain of what .NET is supposed to be all about. Being able
to copy state, though, would be handy.

Reflection :)
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,


OK, please enlighten me. What would be the proper design of the base
class? I see no way to inherit from such a base class, regardless of
the base class design!

Take a look at ANY OOp design book


That is like 101 OOP design
 
M

Mike Schilling

C# is an impressive language...but it seems to have one big limitation
that, from a C++ background, seems unacceptable.

Here's the problem:

I have a third-party Document class. (This means I can't change the
Document class.) I want to extend this (inherit from Document) as
MyDocument, adding new events and application-specific methods and
properties.

I submit that this can't be done in C#.

Consider this example:

class MyDocument : public Document

This doesn't work because the only way to open an existing Document is
using the static method Document.Load(string FileName), which returns a
Document object. There doesn't seem to be any way to convert or cast a
Document object to a MyDocument object. There is therefore no way to
"Load" a MyDocument object!


1. "Wrap" the object, as follows:
class MyDocument
{
protected Document TheDocument;
}

But...this means that I have to wrap EACH of the hundreds of methods
and properties needed to manipulate the Document object. This is
clearly a case for inheritance, to allow the base class properties and
methods to be automatically available, with enhancements from the
derived class.

2. In MyDocument.Load, call Document.Load, and then COPY all of
Document's members to MyDocument.

BUT, this is prohibitive because COPYING all of Document's members is
prohibitive in terms of run time, and also in terms of development
effort (lines of code, and therefore, potential bugs).

In C++, I would do something like this:

class MyDocument : public Document
{
public static MyDocument Load(string FileName)
{
return (MyDocument)Document.Load(FileName);
}
}

To do that, you'd have to define a way to convert Document to MyDocument.
And whatever you do could be done as easily in C# as in C++ (unless you did
something unsafe like memcpy()).
 
M

Mike Schilling

Jon Skeet said:
Instead of having a static method which returns a Document, create an
*instance* method which loads data into an existing instance. That's
the way XmlDocumentLoad works, for example.

Or, if you don't want the "empty" instance to be created (not a problem for
XmlDocument, of course)

1. Write a constructor that takes the filename (or Stream, or Reader,
....) as an argument
2. Have the constructor documented as calling a protected method to load
the instance

You can now inherit by creating a similar constructor in the derived class
and optionally overriding the protected method (if, say, the derived class
extends the file's possible contents.)
 
A

Andy

Actually, I was reading a Java book this weekend, and it seems that
you can do that in Java, likely with the same problems you would
encounter in C++.
 
M

Mike Schilling

Actually, I was reading a Java book this weekend, and it seems that
you can do that in Java, likely with the same problems you would
encounter in C++.

Casts are safe in Java, just as they are in C#. (That should be stated the
other way around, of course.)
 
G

groups

No, it's simply bad design of the base class, or trying to made a bad use of
the class.

You say the base class is designed poorly. So what would a GOOD
design look like? The constraints are:
- Original 'Document' object has been serialized as a 'Document.'
- Reflection (to make a copy) is impractical because it is time-
intensive.
- Wrapping (MyDocument "contains" a Document" is impractical because
of the large numbers of methods that would have to be reproduced.

I assert again that given these constraints (which are not uncommon in
programming), the design of C# (or .NET) doesn't provide a good
answer.

Tony
 
G

groups

Jon,

Yes, this makes sense. But System.Serialization doesn't allow this.
You cann't deserialize a stream into an already existing object.
Deserialization always creates a new object, and you can't assign the
newly deserialized object to 'this'.

Tony
 
M

Mike Schilling

You say the base class is designed poorly. So what would a GOOD
design look like? The constraints are:
- Original 'Document' object has been serialized as a 'Document.'
- Reflection (to make a copy) is impractical because it is time-
intensive.
- Wrapping (MyDocument "contains" a Document" is impractical because
of the large numbers of methods that would have to be reproduced.

I assert again that given these constraints (which are not uncommon in
programming), the design of C# (or .NET) doesn't provide a good
answer.

But you haven't shown a C++ solution either, since the cast in your example
doesn't work.
 

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