Constructors

  • Thread starter Thread starter Peter Morris [Droopy eyes software]
  • Start date Start date
Joanna Carter said:
| Nope. Otherwise virtual method calls being made from the constructor
| couldn't run the overridden implementation in the derived class, which
| they do.

Huh ? You lost me there.

Actually, having reread your statement, mine indeed doesn't follow.
However, the fact that variables can be set before the base class
constructor is executed shows that to some extent at least, the object
*does* exist - the memory must have been allocated, at least, otherwise
those variables wouldn't exist.
| In fact, C# *does* run code before the base class constructor - it
| executes the variable initialisers. (Note that this is different from
| Java, which doesn't even execute the variable initializers before
| running the superclass constructor.)

Picky ! :-)

| I usually find there are ways round this when I really want to do
| something before the constructor code is executed.

Like... ?

Like the ways we've already shown, executing static methods etc.
 
Hi Jon
In this case I'd create a static method which returns a SpecialClass1,
and make the constructor private.

I have this code pattern in my objects too, for example.

SomeClass.ForSiteVisit(SiteVisit)
SomeClass.ForPlannedVisit(PlannedVisit);
SomeClass.ForCustomer(Customer);

I can work out the customer from SiteVisit and PlannedVisit (because in both
cases you are visiting a customer), but this means that I end up
copy/pasting code into each *or* having a static method.

I don't actually have a problem I need to work around, I just find it
annoying that I can't specify at which point I want my base constructor code
called, it's a bit rubbish to be quite blunt about it :-)

Pete
 
Actually, having reread your statement, mine indeed doesn't follow.
However, the fact that variables can be set before the base class
constructor is executed shows that to some extent at least, the object
*does* exist - the memory must have been allocated, at least, otherwise
those variables wouldn't exist.

Yes, a good point! So the object *does* exist before the base is called,
and the constructors are merely initialisation code?

Like the ways we've already shown, executing static methods etc.

They reek too much of "workaround" though don't you think? I think you
should look at code and see the purpose, not look at it and have to try to
understand why it looks so weird.

this.Customer = customer
base(Customer.ObjectSpace);

Perfectly simple!


Pete
 
"Jon Skeet [C# MVP]" <[email protected]> a écrit dans le message de (e-mail address removed)...

| Actually, having reread your statement, mine indeed doesn't follow.
| However, the fact that variables can be set before the base class
| constructor is executed shows that to some extent at least, the object
| *does* exist - the memory must have been allocated, at least, otherwise
| those variables wouldn't exist.

What!! You mean we have to admit that Peter was right ? :-))

| Like the ways we've already shown, executing static methods etc.

Also coming from a Delphi background, I sort of agree with Peter that it
should be possible to have code before the inherited constructor call but,
heyho, times change. After all, I had to do some odd OO things to cope with
some Delphi features, so why not expect similar with C# ? :-)

Joanna
 
Mark said:
This capability is not available in C++, IIRC.
....

I would say so also. Overriden virtual member function in derived class
should not be called at all. It should call the base version. Which kind
of makes sense, because derived object is not constructed yet.

Regards,
Goran
 
Joanna Carter said:
"Thomas T. Veldhouse" <[email protected]> a ?crit dans le message de (e-mail address removed)...

| Gotcha ... I didn't know that. Good old Microsoft ate up its little
cousin
| ;-)

Whoa!! Delphi is still very much alive and well. What is more it is one of
the few languages that can provide a single code base that will compile to
both Win32 *and* .NET.

I like C++ on Qt ... it will compile to Win32, Linux (multilib), FreeBSD,
Soloaris ... etc ;-)

But ... my clients like it when I offer .NET solutions, so I give them what
they want. :-)
 
Jon Skeet said:
Actually, having reread your statement, mine indeed doesn't follow.
However, the fact that variables can be set before the base class
constructor is executed shows that to some extent at least, the object
*does* exist - the memory must have been allocated, at least, otherwise
those variables wouldn't exist.


Like the ways we've already shown, executing static methods etc.

Static methods do not get around the problem, because they can not be virtual
[if they could, by definition, they could not be static].
 
What!! You mean we have to admit that Peter was right ? :-))>

/me polishes knuckles :-)
 
Goran Sliskovic said:
...

I would say so also. Overriden virtual member function in derived class
should not be called at all. It should call the base version. Which kind
of makes sense, because derived object is not constructed yet.

This is an interesting difference between C++ and C#. In C++ the type of
this changes
through the ctor chain; but in C# (and C++/CLI I think) it is the same.

Which, of course, is why calling virtual methods in ctors in C# is tricky:
since some of
the base class ctors might not have been executed, the object may not be
fully constructed.
 
Peter Morris said:
Yes, a good point! So the object *does* exist before the base is called,
and the constructors are merely initialisation code?
Yup.


They reek too much of "workaround" though don't you think? I think you
should look at code and see the purpose, not look at it and have to try to
understand why it looks so weird.

Agreed. I'm not sure I'm qualified to comment on why it is the way it
is though - there may well be good reasons we haven't thought of.
 
Thomas T. Veldhouse said:
Like the ways we've already shown, executing static methods etc.

Static methods do not get around the problem, because they can not be virtual
[if they could, by definition, they could not be static].

I see no indication that virtual methods are required in any of Peter's
situations.
 
Jon Skeet said:
I see no indication that virtual methods are required in any of Peter's
situations.

Sure, as long as everything that is "persisted" is scoped such that it is
available to the static method. So, are you indicating that all instances
that make up his composite object graph be scoped to at least "internal"?
 
Thomas T. Veldhouse said:
Sure, as long as everything that is "persisted" is scoped such that it is
available to the static method. So, are you indicating that all instances
that make up his composite object graph be scoped to at least "internal"?

I don't see why that's required. The only thing you lose is the ability
to change the filtering logic (or validation, or whatever) on a per-
derived-class basis - and there's no indication that that's required.

Could you give an example using Peter's template code as a starting
point of what couldn't be done?
 
Jon Skeet [C# MVP] wrote:
....
Actually, having reread your statement, mine indeed doesn't follow.
However, the fact that variables can be set before the base class
constructor is executed shows that to some extent at least, the object
*does* exist - the memory must have been allocated, at least, otherwise
those variables wouldn't exist.
....
Yes (at least in C++, memory is allocated for whole object to avoid
obvious problems), however, class may not be in valid state (it could be
in state where invariants do not hold). I don't mean some internal CLR
state, but state visible to it's clients. Calling a method when the
invariants may not hold is risky. It can create lot of maintanance
problems later (when somebody changes something not knowing method is
called before derived construtor has been executed). I'd avoid it at if
I can.

Regards,
Goran
 
A *very* basic case, it may not make sense but it is a simplified example.

public class PersistentObject
{
public readonly object ObjectSpace;
public PersistentObject(object objectSpace)
{
this.ObjectSpace = objectSpace;
AfterConstruction();
}

protected virtual void AfterConstruction() {}
}

public class Customer : PersistentObject
{
public readonly object Country;
public Customer(PersistentObject country) : base(country.ObjectSpace)
{
this.Country = country;
}

protected override void AfterConstruction()
{
//Do something with this.Country
}
}


If I could call the base constructor after setting this.Country then it
would work perfectly.


Pete
 
Peter Morris said:
A *very* basic case, it may not make sense but it is a simplified example.

Okay, I see your point. If you want a really, really grotty hack way of
solving it, I've got one - but it's so shameful that I'll keep it to
myself unless pressed :)

In general though, I'd strongly recommend avoiding calling virtual
methods from constructors, for the reasons Goran stated - it's hard to
guarantee that appropriate invariants etc are in place before the
object is fully constructed.
 
Okay, I see your point. If you want a really, really grotty hack way of
solving it, I've got one - but it's so shameful that I'll keep it to
myself unless pressed :)

*press*press*press* :-)

In general though, I'd strongly recommend avoiding calling virtual
methods from constructors, for the reasons Goran stated - it's hard to
guarantee that appropriate invariants etc are in place before the
object is fully constructed.

In my example a new constructor is introduced in order to ensure that
"Customer" is passed to the new instance, then the original ObjectSpace
constructor is called.

PersistentObject's constructor will keep a reference to the ObjectSpace and
then register this object with the object space

this.ObjectSpace.RegisterInstance(this);

The object space knows if it is loading from the persistence service or not
(the object doesn't on account it doesn't know it is even persistent), if
the object is created as a result of a fetch then it is simply instantiated,
if the persistence service is not loading objects then this is a new
instance so the virtual AfterConstruction is called.

AfterConstruction is a method that is only ever called the very first time
an object is created so that it may initiate composite object instances (eg,
Customer.Address), when it is "recreated" from DB these objects will already
exist and therefore not need creating.

I just thought I'd explain why this virtual method exists, basically it is
so that I don't have to have code like this in my constructors

......
{
if (!ObjectSpace.IsLoading)
{
this.Address = new Address(ObjectSpace);
}
}

I don't like my objects to know about persistence if at all possible.


Pete
 
Peter Morris said:
*press*press*press* :-)

Use a thread-local (static) variable which is set in the static method
(see other solutions for how to introduce a call to a static method),
and then use it in the overridden method to populate the instance
variable.

Now excuse me while I wash my hands ;)
In my example a new constructor is introduced in order to ensure that
"Customer" is passed to the new instance, then the original ObjectSpace
constructor is called.

I just thought I'd explain why this virtual method exists, basically it is
so that I don't have to have code like this in my constructors

.....
{
if (!ObjectSpace.IsLoading)
{
this.Address = new Address(ObjectSpace);
}
}

I don't like my objects to know about persistence if at all possible.

But aren't you effectively introducing that anyway by having the
AfterConstruction method at all? You've got to explain why the
AfterConstruction method is present, and moving the logic to the
constructor just makes it more explicit (and therefore easier to
understand, IMO.)

I'm probably missing more though - it's late and I'm tired :(
 
Joanna said:
Delphi, C#'s [spiritual] parent
[...] does allow code before inherited constructor calls.

Perhaps someone could ask Anders Heljsberg why he changed his mind about
this?
 
Perhaps someone could ask Anders Heljsberg why he changed his mind about

You know, that would be a really interesting question to see an answer to!
 
Back
Top