.NET Forum / .NET Framework / New Users / March 2006
Copy constructor?
|
|
Thread rating:  |
Axel Dahmen - 22 Feb 2006 21:05 GMT 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
Daniel O'Connell [C# MVP] - 23 Feb 2006 05:11 GMT > Hi, > [quoted text clipped - 18 lines] > 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());
Axel Dahmen - 23 Feb 2006 09:25 GMT Thanks for trying to help...
> > Is it possible to create kind of a copy constructor in C#, like > > [quoted text clipped - 5 lines] > 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
Nick Hounsome - 23 Feb 2006 12:33 GMT 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, >> [quoted text clipped - 21 lines] > No, the language doesn't support copy constructors. You'd have to do > MyTypedClass mtc = new MyTypedClass(new MyGenericClass()); Axel Dahmen - 23 Feb 2006 13:42 GMT 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
---------------------------
> What are you really trying to do? > [quoted text clipped - 50 lines] > > No, the language doesn't support copy constructors. You'd have to do > > MyTypedClass mtc = new MyTypedClass(new MyGenericClass()); Nick Hounsome - 23 Feb 2006 16:41 GMT > Hi Nick, > [quoted text clipped - 26 lines] > 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 [quoted text clipped - 4 lines] > 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, [quoted text clipped - 14 lines] > TIA, > Axel Dahmen Axel Dahmen - 23 Feb 2006 18:05 GMT > 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...
> > 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. 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
Axel Dahmen - 23 Feb 2006 19:24 GMT 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
----------------------------
> > It is typical MS bad form to use magic implementation specific stuff for > > this (DataRowBuilder). [quoted text clipped - 22 lines] > Thanks for all your efforts! > Axel Nick Hounsome - 24 Feb 2006 08:17 GMT >> It is typical MS bad form to use magic implementation specific stuff for >> this (DataRowBuilder). [quoted text clipped - 13 lines] > 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.
Axel Dahmen - 24 Feb 2006 10:01 GMT > 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
Daniel O'Connell [C# MVP] - 25 Feb 2006 07:51 GMT >> Please persist with the virtual method solution if possible as it is much >> preferable to reflection for a number of reasons. [quoted text clipped - 11 lines] > 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).
Axel Dahmen - 10 Mar 2006 18:31 GMT > 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
Daniel O'Connell [C# MVP] - 10 Mar 2006 21:03 GMT >> 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. 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.
>> 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. 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, [quoted text clipped - 15 lines] > > 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.
>> In your case, I get the impression you just want another view. A copy > isn't [quoted text clipped - 13 lines] > 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
Nick Hounsome - 23 Feb 2006 16:43 GMT 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.
> Hi Nick, > [quoted text clipped - 115 lines] >> > No, the language doesn't support copy constructors. You'd have to do >> > MyTypedClass mtc = new MyTypedClass(new MyGenericClass());
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|