Copy constructor?

  • Thread starter Thread starter Axel Dahmen
  • Start date Start date
A

Axel Dahmen

Hi,

I have created a class adding some Functionality to a generic class and
derived it from that:

class MyTypedClass : MyGenericClass
{}

Within a class library project, all functions work with the generic version,
but in my Web Application project I'm dealing with the derived version
(basically adding type to the generic version). But the following doesn't
seem to be possible:

MyTypedClass mtc = (MyTypedClass)(new MyGenericClass());

Is it possible to create kind of a copy constructor in C#, like

class MyTypedClass : MyGenericClass
{
public MyTypedClass(MyGenericClass mgc) : base(mgc) {}
}

TIA,
Axel Dahmen
 
Axel Dahmen said:
Hi,

I have created a class adding some Functionality to a generic class and
derived it from that:

class MyTypedClass : MyGenericClass
{}

Within a class library project, all functions work with the generic
version,
but in my Web Application project I'm dealing with the derived version
(basically adding type to the generic version). But the following doesn't
seem to be possible:

MyTypedClass mtc = (MyTypedClass)(new MyGenericClass());

Is it possible to create kind of a copy constructor in C#, like

class MyTypedClass : MyGenericClass
{
public MyTypedClass(MyGenericClass mgc) : base(mgc) {}
}

No, the language doesn't support copy constructors. You'd have to do
MyTypedClass mtc = new MyTypedClass(new MyGenericClass());
 
Thanks for trying to help...

No, the language doesn't support copy constructors. You'd have to do
MyTypedClass mtc = new MyTypedClass(new MyGenericClass());


Sorry, I didn't get that. What is the difference between your line and my
given prototype? What should the constructor prototype look like to make
up-casts possible?

IMHO, if the derived class doesn't introduce new fields, then up-casting
should not throw an InvalidCastException.

Why can typed DataSets up-cast DataRows to typed DataRows and why do I get a
runtime exception if I do the same?

public UsersRow NewUsersRow() {
return ((UsersRow)(this.NewRow()));
}

Your help is quite appreciated!

Tnx,
Axel Dahmen
 
What are you really trying to do?

MyTypedClass mtc = (MyTypedClass)(new MyGenericClass()); // ????????

What is wrong with:

MyTypedClass mtc = new MyTypedClass();

If you want a copy of an existing object then implement ICloneable in both
base and derived (+ a typesafe overload)

class MyTypedClass : MyGenericClass, ICloneable
{
public object ICloneable.Clone()
{
return Clone();
}

public MyTypedClass Clone()
{
return aCopy;
}
}

MyGenericClass mtc1 = new MyTypedClass();

MyTypedClass mtc1 = mtc1.Clone(); // doesn't require knowledge of
MyTypeClass here
 
Hi Nick,

problem is that I only have a base class object which I need to *cast* to a
derived object. So, basically, my situation is something like this:

MyBaseClass mbc = new MyBaseClass(..., ..., ..., ...);
MyTypedClass mtc = (MyTypedClass)mbc; // throws InvalidCastException

Disturbing part: MyTypedClass doesn't add any fields, so the cast ist
perfectly safe.


When I have VS2003 create a typed DataSet using an xsd, it does the same,
but there it works:

public class UsersRow : DataRow
{
...

public UsersRow NewUsersRow()
{
return ((UsersRow)(this.NewRow())); // NewRow() returns a DataRow;
}

...
}

Disturbing part II: UsersRow in fact *adds* new fields to DataRow. Why does
it work?


To get more into detail, cloning would yield a huge overhead. MyBaseClass is
a tree object having a collection of MyBaseClass children. I don't create it
using a constructor, instead I use a static factory function to create a
whole tree of objects and return only the root:

MyBaseClass mbc = MyBaseClass.CreateHierarchy(..., ..., ..., ...);
MyTypedClass mtc = (MyTypedClass)mbc; // throws InvalidCastException

MyBaseClass is based in a separate Common project, therefore it is untyped,
i.e. only provides properties through a [] operator (in fact it forwards the
operator to a private DataRow member).

In my object I now want to provide typed access to each of the properties,
like

string Street { get {return base["Street"];}}

That's why I need the cast. It's basically the same methodology like with
MS' typed DataSets.

Any quick help is highly appreciated!!!

TIA,
Axel Dahmen
 
Axel Dahmen said:
Hi Nick,

problem is that I only have a base class object which I need to *cast* to
a
derived object. So, basically, my situation is something like this:

MyBaseClass mbc = new MyBaseClass(..., ..., ..., ...);
MyTypedClass mtc = (MyTypedClass)mbc; // throws InvalidCastException

Disturbing part: MyTypedClass doesn't add any fields, so the cast ist
perfectly safe.


When I have VS2003 create a typed DataSet using an xsd, it does the same,
but there it works:

public class UsersRow : DataRow
{
...

public UsersRow NewUsersRow()
{
return ((UsersRow)(this.NewRow())); // NewRow() returns a DataRow;
}

...
}

Disturbing part II: UsersRow in fact *adds* new fields to DataRow. Why
does
it work?

If you look at the generated code it overrides a protected virtual method
called NewRowFromBuilder which creates a new row of the correct type. The
inference is that although NewRow is not itself virtual it calls
NewRowFromBuilder which is. No magic. No copy constructors. No explicit cast
methods.

i.e. it isn't casting it is plain old virtual method calls.

It is typical MS bad form to use magic implementation specific stuff for
this (DataRowBuilder).
To get more into detail, cloning would yield a huge overhead.

I don't understand. Either you want a copy or you don't - If you do then
Clone() is what you need. If you don't then just make a virtual method
called CloneSchema() or something which doesn't copy the data.
MyBaseClass is
a tree object having a collection of MyBaseClass children. I don't create
it
using a constructor, instead I use a static factory function to create a
whole tree of objects and return only the root:

MyBaseClass mbc = MyBaseClass.CreateHierarchy(..., ..., ..., ...);
MyTypedClass mtc = (MyTypedClass)mbc; // throws InvalidCastException

This can never work the way DataSet.NewRow() does.
DataSet can do magic through virtual methods because it is an instance
method.

You are using a static method so the only way you could manage it is using
types and reflection by passing typeof(MyBaseClass) as a parameter.
MyBaseClass is based in a separate Common project, therefore it is
untyped,
i.e. only provides properties through a [] operator (in fact it forwards
the
operator to a private DataRow member).

In my object I now want to provide typed access to each of the properties,
like

string Street { get {return base["Street"];}}

That's why I need the cast. It's basically the same methodology like with
MS' typed DataSets.

Any quick help is highly appreciated!!!

TIA,
Axel Dahmen
 
I forgot to mention in my last post that the one way you could acheive the
syntax that you are looking for is by creating an explicit cast operator in
each derived class.

IMHO this is inferior to the virtual method approach as it requires a wasted
temporary base class object.

Axel Dahmen said:
Hi Nick,

problem is that I only have a base class object which I need to *cast* to
a
derived object. So, basically, my situation is something like this:

MyBaseClass mbc = new MyBaseClass(..., ..., ..., ...);
MyTypedClass mtc = (MyTypedClass)mbc; // throws InvalidCastException

Disturbing part: MyTypedClass doesn't add any fields, so the cast ist
perfectly safe.


When I have VS2003 create a typed DataSet using an xsd, it does the same,
but there it works:

public class UsersRow : DataRow
{
...

public UsersRow NewUsersRow()
{
return ((UsersRow)(this.NewRow())); // NewRow() returns a DataRow;
}

...
}

Disturbing part II: UsersRow in fact *adds* new fields to DataRow. Why
does
it work?


To get more into detail, cloning would yield a huge overhead. MyBaseClass
is
a tree object having a collection of MyBaseClass children. I don't create
it
using a constructor, instead I use a static factory function to create a
whole tree of objects and return only the root:

MyBaseClass mbc = MyBaseClass.CreateHierarchy(..., ..., ..., ...);
MyTypedClass mtc = (MyTypedClass)mbc; // throws InvalidCastException

MyBaseClass is based in a separate Common project, therefore it is
untyped,
i.e. only provides properties through a [] operator (in fact it forwards
the
operator to a private DataRow member).

In my object I now want to provide typed access to each of the properties,
like

string Street { get {return base["Street"];}}

That's why I need the cast. It's basically the same methodology like with
MS' typed DataSets.

Any quick help is highly appreciated!!!

TIA,
Axel Dahmen




---------------------------
Nick Hounsome said:
What are you really trying to do?

MyTypedClass mtc = (MyTypedClass)(new MyGenericClass()); // ????????

What is wrong with:

MyTypedClass mtc = new MyTypedClass();

If you want a copy of an existing object then implement ICloneable in
both
base and derived (+ a typesafe overload)

class MyTypedClass : MyGenericClass, ICloneable
{
public object ICloneable.Clone()
{
return Clone();
}

public MyTypedClass Clone()
{
return aCopy;
}
}

MyGenericClass mtc1 = new MyTypedClass();

MyTypedClass mtc1 = mtc1.Clone(); // doesn't require knowledge of
MyTypeClass here
 
It is typical MS bad form to use magic implementation specific stuff for
this (DataRowBuilder).

That's what I call unfair... Leaving us software developers out with an
incomplete solution, but using backdoors themselves...

I don't understand. Either you want a copy or you don't - If you do then
Clone() is what you need. If you don't then just make a virtual method
called CloneSchema() or something which doesn't copy the data.

I must admit that I don't understand your solution. These are the concerns I
have: If Clone() yields an Object, I still have to cast that object to
MyTypedClass. But won't this cast throw InvalidCastException like a direct
cast would? And if not, would the following be valid:

MyTypedClass mtc = (MyTypedClass)(object)mbc

Thanks for enlightening me!


BTW: I can't use the explicit operator as it yields a compiler error:
"Compiler Error CS0553: user defined conversion to/from base class".

Thanks for all your efforts!
Axel
 
IT FINALLY WORKS !!!

:)))))


I'm using Reflection now and it's working smoothly so far... Just got to add
having different types on each child level.

This code is doing the magic in UserBase.CreateUserHierarchy (in the new
version I'm providing the destination type as a parameter):


UserBase curUB;
ConstructorInfo constr;

constr=type.GetConstructor(new Type[]{typeof(DataSet),typeof(DataSet)
,typeof(Type),typeof(DataRow),typeof(DataColumn)
,typeof(UserBase),typeof(int)});

curUB=(UserBase)constr.Invoke(new object[]{userTblSet,roleTblSet
,type,row,pkCol,parent,tabOffset});


This cost me another 10 years of my life today... Thanks to all for helping
me..

Axel



----------------------------
 
Axel Dahmen said:
That's what I call unfair... Leaving us software developers out with an
incomplete solution, but using backdoors themselves...



I must admit that I don't understand your solution. These are the concerns
I
have: If Clone() yields an Object, I still have to cast that object to
MyTypedClass. But won't this cast throw InvalidCastException like a direct
cast would? And if not, would the following be valid:

Your problem is that for some reason you seem think that the cast is
actually changing the object. It isn't. In all the virtual method solutions
the object really IS a MyTypedClass (because it is created as such by the
overloaded method) it is just initially known as an instance of its base
class. It is not casting in the same sense as casting an int to a float say
which actually changes something.

object Clone()
{
return new MyTypedClass(.....);
}

The object returned is NOT a cut down, transformed or sliced MyTypedClass it
IS a MyTypedClass (as can be proved if you call GetType()) so casting it
back to MyTypedClass just involves checking to see that it really is one.
MyTypedClass mtc = (MyTypedClass)(object)mbc

Only works if mbc realy is a MyTypedClass (the cast to object is useless).
Thanks for enlightening me!


BTW: I can't use the explicit operator as it yields a compiler error:
"Compiler Error CS0553: user defined conversion to/from base class".

Of course - I should have thought of that.
Thanks for all your efforts!
Axel

Please persist with the virtual method solution if possible as it is much
preferable to reflection for a number of reasons.
 
Please persist with the virtual method solution if possible as it is much
preferable to reflection for a number of reasons.

I can't as some of the properties are readonly for a good reason. So I can
only create objects from within the constructor. Another one is that
CreateObjectHierarchy() is static, thus virtual calls of this function are
not possible.

I know Reflection (=late binding) is only a hack. Upcasting would be the
right solution here. I'm normally working with virtual functions wherever
feasible. But it is not feasible in this case. Upcasting would, also for a
number of other scenarios where you just want to add additional
functionality to given objects for example. A copy constructor could be
rather helpful here and IMHO should be considered of being implemented by
MS.

Axel
 
Axel Dahmen said:
I can't as some of the properties are readonly for a good reason. So I can
only create objects from within the constructor. Another one is that
CreateObjectHierarchy() is static, thus virtual calls of this function are
not possible.

I know Reflection (=late binding) is only a hack. Upcasting would be the
right solution here. I'm normally working with virtual functions wherever
feasible. But it is not feasible in this case. Upcasting would, also for a
number of other scenarios where you just want to add additional
functionality to given objects for example. A copy constructor could be
rather helpful here and IMHO should be considered of being implemented by
MS.

There are some messy things that would have to be dealt with if you added
copy constructors. Right now there is no object slicing, types aren't
defined by their data order(by which I mean you don't have "well, they both
hold an int" to deal with,) the complexity of assignments grows more, and
cloning isn't constrained by the messiness of copy constructors(basically,
since copy constructors aren't polymorphic in nature its quite easy to lose
data, something that isn't currently possible in .NET.)

Add copy constructors and you have a whole host of things that have to be
figured out. Are they allowed strictly for upcasting? What if their are new
fields? How does the compiler deal with dataloss? Do we actually want to
create copies or is it simply another view we are trying to get?

In your case, I get the impression you just want another view. A copy isn't
the right thing to do here, IMHO, since you are wasting memory and
complicating state management(assuming there *is* state management) for no
clear reason. Encapsulation would probably be my first thought(and that
would get you over the explicit conversion problem).
 
Add copy constructors and you have a whole host of things that have to be
figured out. Are they allowed strictly for upcasting?

Well, it would help a great deal if at least upcasting was possible. Just
adding a couple of member functions to a base class (by creating a derived
class with no new fields) should not throw an InvalidCastException.

What if their are new fields?

Like I said in one of my previous posts: If there are no new fields, then
upcasting will not be a problem because there's nothing added to the object.
This option should be available automatically using no copy constructor.

If there are new fields introduced by the deriving class then an explicit
constructor is required, utilizing a copy constructor, provided by .NET,
like:


public MyDerivedClass(MyBaseClass baseClass) : base(baseClass)
{
...
}


plus explicit conversion operator, like:

public static explicit operator MyDerivedClass (MyBaseClass baseClass)
{
return new MyDerivedClass(baseClass);
}

How does the compiler deal with dataloss?

There is no dataloss.

Do we actually want to create copies or is it simply another view we are
trying to get?

Upcasting (= no new fields introduced) is simply another view. Creating a
new class would require a silent and shallow copy.

In your case, I get the impression you just want another view. A copy isn't
the right thing to do here, IMHO, since you are wasting memory and
complicating state management(assuming there *is* state management) for no
clear reason. Encapsulation would probably be my first thought(and that
would get you over the explicit conversion problem).

No...

a) encapsulation (=aggregation) will add unnecessary overhead to my
implementation as I would need to provide each and every functionality from
the base class in my derived class just to call my encapsulated member.

b) I can't downcast if I just encapsulate. I need to derive from a base
class.


Axel Dahmen
 
Axel Dahmen said:
Well, it would help a great deal if at least upcasting was possible. Just
adding a couple of member functions to a base class (by creating a derived
class with no new fields) should not throw an InvalidCastException.

It would be nice ocassionally, but I don't think its worth the
compiler\language complexity nor does it seem like something that would be
used consistently. I'm quite sure you should be able to work around it
easily.
Like I said in one of my previous posts: If there are no new fields, then
upcasting will not be a problem because there's nothing added to the
object.
This option should be available automatically using no copy constructor.
That isn't the point. It adds complexity. What if there are new fields? What
errors should the compiler emit? How do you make it simple and easy for
everyone to understand? How do you do it in a language independent manner(or
do you?) Is it valuable across a wide range of users? Its alot to consider
for a feature that may only be really useful to C++ developers that dabble
in C# and occasionally useful to the regular C# dev.
If there are new fields introduced by the deriving class then an explicit
constructor is required, utilizing a copy constructor, provided by .NET,
like:


public MyDerivedClass(MyBaseClass baseClass) : base(baseClass)
{
...
}


plus explicit conversion operator, like:

public static explicit operator MyDerivedClass (MyBaseClass baseClass)
{
return new MyDerivedClass(baseClass);
}



There is no dataloss.

I dislike explicit operators and copy constructors both, so I don't like
this much. Not only does it rewrite some base rules, it has some potential
problems, which I'll address later.

There could also be data loss, quite easily. Consider this scenario which
illustrates why you can't convert a base type to a derived type and where
dataloss can occur:

Considering these classes:

class MyBaseClass
{
string stringA;
}

class MyDerivedClass : MyBaseClass
{
void NewMethod();
}

class MyDerivedClass2 : MyBaseClass
{
string apple;
}

how does this code work out?

MyBaseClass mbc = new MyDerivedClass2();
MyDerivedClass mdc = <MyDerivedClass>mbc;


The copy constructor can lose data and the user wouldn't be able to tell,
especially if MyDerivedClass2 is returned by another component instead of
being constructed right there. You could use a runtime error, but that will
eventually just come down ontop of the end user. It's to easy to mess this
up, probably worse than casting as it stands, which is pretty messy, IMHO.
Someone else will just have the same problem you are, just in a slightly
different way. Language features like this should really be resolvable at
compile time, IMHO.

No...

a) encapsulation (=aggregation) will add unnecessary overhead to my
implementation as I would need to provide each and every functionality
from
the base class in my derived class just to call my encapsulated member.

b) I can't downcast if I just encapsulate. I need to derive from a base
class.

You appear to only have one dataset. It'd be pretty simple to build a series
of explicit conversions or constructors from the dataset class to the
functionality class instead of up and down casting.

FilterXClass fxc = new FilterXClass(data);

Also, out of curiosity, have you looked into the proposed extension methods
from C# 3.0[1]? Assuming they survive into the final product, you'd be able
to sort of paste on methods from other classes based on using statements
instead of having to cast around for new functionality. Its kinda ugly, but
it is a possiblity.

1. http://dotnet.org.za/ernst/archive/2005/11/19/48385.aspx
 
Back
Top