Constructors

  • Thread starter Peter Morris [Droopy eyes software]
  • Start date
J

Jon Skeet [C# MVP]

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.
 
P

Peter Morris [Droopy eyes software]

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
 
P

Peter Morris [Droopy eyes software]

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
 
J

Joanna Carter [TeamB]

"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
 
G

Goran Sliskovic

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
 
T

Thomas T. Veldhouse

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. :)
 
T

Thomas T. Veldhouse

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].
 
P

Peter Morris [Droopy eyes software]

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

/me polishes knuckles :)
 
M

Michael Taylor

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.
 
J

Jon Skeet [C# MVP]

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.
 
J

Jon Skeet [C# MVP]

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.
 
T

Thomas T. Veldhouse

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"?
 
J

Jon Skeet [C# MVP]

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?
 
G

Goran Sliskovic

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
 
P

Peter Morris [Droopy eyes software]

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
 
J

Jon Skeet [C# MVP]

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.
 
P

Peter Morris [Droopy eyes software]

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
 
J

Jon Skeet [C# MVP]

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 :(
 
L

Larry Lard

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?
 
P

Peter Morris [Droopy eyes software]

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!
 

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