constructor

L

linkspeed

Following texts are from C# spec.

The optional constructor-initializer specifies another instance
constructor to invoke before executing the statements given in the
constructor-body of this instance constructor. This is described
further in Section 10.10.1.


So this means:

public class c1
{
(1)public c1(int i) : this(i, i)
{
}

(2)public c1(int i, int j)
{
}
}

constructor (2) will be called before constructor (1).

It is OK for simple parameters. What if parameter j can only get from
a long and complex calculation? This requires the body of constructor
(1) is called before constructor (2).


How can we do this in C#?

Thanks
linkspeed
 
D

Daniel O'Connell

linkspeed said:
Following texts are from C# spec.

The optional constructor-initializer specifies another instance
constructor to invoke before executing the statements given in the
constructor-body of this instance constructor. This is described
further in Section 10.10.1.


So this means:

public class c1
{
(1)public c1(int i) : this(i, i)
{
}

(2)public c1(int i, int j)
{
}
}

constructor (2) will be called before constructor (1).

It is OK for simple parameters. What if parameter j can only get from
a long and complex calculation? This requires the body of constructor
(1) is called before constructor (2).


How can we do this in C#?

This is an annoying limitation. You are pretty much required to use a
private static member to perform the calculation and return the proper value
for the parameter as there is no way to call this() or base() from within a
constructor.
 
G

Guest

What you shoudl do then is have a .Start or .Init member that must be called
before anything works. Until thats called, throw an exception to enforce it.
 
D

Daniel O'Connell

That is because "this" is NOT a valid reference until the ctor has exited.
You should actually look into that. "this" can be used in a constructor(and
is implicitly used *quite* often, you shouldn't use it with regard to
virtual methods, but that is another issue all together. The issue is
because the C# team decided to not allow constructor calls from within a
constructor. It has to be done before a constructor body has been
executed(this is done for reasons of simplicitly, you should usually call
the base constructor before touching any instance members, the C# syntax
forces this, others do not).

In reply to your other post, that isn't a pattern I'd recommend in most
cases. If you expect the end user to call it, you have a huge problem: you
are forcing what effictivly is two constructors on the user. If you expect
inheriting code to call it you leave yourself with a method that can royally
screw your class if called by a method outside of the constructor, or result
in stupid bugs if its missed(or what if its called twice? The what ifs get
to be too complex). In most cases this is by far the worst path.

I would almost always recommend a factory, which would be a static method or
instance class(usually referenced statically) that generates your object,
performing the calculations instead of relying on constructors or by using a
private static method to perform the work of parameter calcuation over using
a generic Init method.

Now, I've said in most cases a number of times. There are situations where
an object should have an initalizing method, but usually that method should
be used in a loading sense. Such an example can be seen on XmlDocument,
where the document is capable of loading an Xml node *after* its creation.
Ideally this method should be designed to allow your class to start from
scratch on new data and should probably only be done when the end user will
have a simplier time because of it. Other reasons may be to avoid
constructor requirements when using an interface based system, or what
amounts to the interface itself needs to be initalized with specific data.
This can often be circumvented with an appropriate factory, however.
 
G

Guest

It might be worth explaining this a little further Linkspeed. Do you mean that when you create your class, you need to perform a calculation on a parameter that is then stored within the class? If you cant call one constructor over another because of this, then I would suspect maybe the approach needs revising. It is right the object should do the calculation, so why not pass in the parameters and let the object perform the calculation? In your situation a client of the class could invoke the second constructor - how do you know the vlaue being passed in is correct? Who calculated it? Why didnt this object calculate it?

----- linkspeed wrote: -----

Following texts are from C# spec.

The optional constructor-initializer specifies another instance
constructor to invoke before executing the statements given in the
constructor-body of this instance constructor. This is described
further in Section 10.10.1.


So this means:

public class c1
{
(1)public c1(int i) : this(i, i)
{
}

(2)public c1(int i, int j)
{
}
}

constructor (2) will be called before constructor (1).

It is OK for simple parameters. What if parameter j can only get from
a long and complex calculation? This requires the body of constructor
(1) is called before constructor (2).


How can we do this in C#?

Thanks
linkspeed
 
N

Nick

You won't be able to use that syntax but you can do the following

c1(int i) {
int j;
// process j;
this(i, j);
}

I think I have seen this work before, but let me know if this violates
something.
 
N

Nick

Nick that wont compile.

Nick said:
You won't be able to use that syntax but you can do the following

c1(int i) {
int j;
// process j;
this(i, j);
}

I think I have seen this work before, but let me know if this violates
something.
 
L

linkspeed

Thanks for all posts.

There are some workarounds for that problem,
but a futher question is:

from language design point, does this kind of contructor
calling style in C# have any advantage?
 
D

Daniel O'Connell

Its purpose is to ensure the order of constructor calls. By forcing this
syntax it is possible to ensure that a base constructor will always be
called before a constructor accesses an instance member. It was a choice
made based on common usage I imagine. It *usually* isn't a problem. Often
times when it causes a problem you need to re-examine your design(I've run
into it a few times as well).
 

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