What's 'best practice'--instantiate in the constructor or outside it for collection class?

R

raylopez99

Question: the "myList" below is the same (works the same) whether
instantiated inside the (normal) constructor, as below, and as my
standard practice, or outside?

RL

public class AClass
{
int j;

//public List<Node> myList = new List<Node>(); // less safe
here?

public List<Node> myList; //definition; declaration in normal
constructor

public AClass()
{
j =0;
myList = new List<Node>();
}

}
 
H

Hakan Fatih YILDIRIM

Hi,
Maybe you can create mylist with private and then you can set and get
the mylist type data from property.You can set it read only or
writeonly by this way.It can be safier.

Hakan Fatih YILDIRIM
MCP
 
U

UL-Tomten

[...] is the same [...]?

No, the base constructor (in your case, "object()") will be called
after myList is initialized if you initialize it in the declaration,
and vice versa. This may cause complications if you have complex
inheritance. The best practice in this case is probably to initialize
in the constructor, since the compiler will move the initialization
there anyway, unless you want a class to have access to variables
initialized in a derived class.
 
R

Rene

Hi UL-Tomten.
No, the base constructor (in your case, "object()") will be called
after myList is initialized if you initialize it in the declaration,
and vice versa. This may cause complications if you have complex
inheritance.

Would you mind elaborating a little more on what you mean by "This may cause
complications if you have complex inheritance."?

The reason I am a little confused about you comment is because as far as I
know, base classes don't know anything about the classes that are inheriting
form them, so if they don't know anything about them, how can they modify
any of their variables?

The only way that I can think that something could go wrong is if the base
class has virtual methods that are overridden by inheritors thus having the
capability of changing variable values that way, but as far as I know, you
can't call virtual methods from constructors.

Thanks in advance.
 
U

UL-Tomten

Would you mind elaborating a little more on what you mean by "This may cause
complications if you have complex inheritance."?

You're in luck: Sunday is my elaboration day. My point was that
typically, you don't need to think about details about when
constructors are run, and when variables are initialized. This is
true, I think, for instance and static members both. The CLR is pretty
POLS in this respect. However, if you make heavy use of base classes,
and make heave use of constructor logic in both base and derived
classes, you may reach a point where you lose overview of exactly what
happens when. In this case, it may be better to be verbose in your
code about when things happen, and IMHO, that means not using
declaration along with initialization for fields (which I would say is
done for brevity).

This is a typical quiz question, which means you shouldn't assume
anyone reading/using your code will know it.
The only way that I can think that something could go wrong is if the base
class has virtual methods that are overridden by inheritors

http://www.bartdesmet.net/images/CQuizFieldinitializationcontd_B5D2/image0_thumb4.png
 
U

UL-Tomten

Well I'll be a monkeys uncle, I was sure you would get a compile error if
you called virtual functions from constructors [...]

Well, it might be hard for the compiler to trap secondary virtual
calls in the ctor.

FxCop and VS Code Analysis will discourage this. So tell your niece
there'll be no bananas for the rulebreakers.
 
R

raylopez99

A good part of an hour wasted! I looked at your example here:
http://www.bartdesmet.net/images/CQuizFieldinitializationcontd_B5D2/image0_thumb4.png

After erecting a lot of scaffolding, and beating my head against the
wall, and thinking I've gone crazy, I've concluded that this program
does not appear to work as expected due to an optical illusion that
has something to do with the way "ToString()" is implimented for base
classes. Or so it seems.

Anyway, a great example of how these virtual table type languages do
stuff behind the scenes that are counterintutive.

Below is my dissected version of your example.

I'd like to know your interpretation of what your program does.

RL


class Foo
{
private int i=69;
public Foo ()
{
i = 99;
Console.WriteLine("!{0}", ToString()); //same as below
// Console.WriteLine("!{0}", this.ToString());
}
public Foo(int eye)
{
i = eye;
Console.WriteLine("!Foo base loves explicit initialization
outside of constructor always! {0}", this.ToString());
}
}
class Bar1 : Foo
{
private int i=321; //overrides the normal constructor always
(at least for ToString)
// private int i; // gives zero, i=123; never called

public Bar1() //public Bar1 ():base() //same thing, not what
you think
{
i = 123;
}
public Bar1(int k): base(k) //still not called, ever!
(for .ToString)
{
Console.WriteLine("Bar1's i is: {0}", k);
i = k;
}

public override string ToString()
{

return ("Hi" + i.ToString()); //
}
}
class Bar2 : Foo
{
// private int i=1234; //overrides constructor always
private int i; //try this now: gives zero, not 10001, always,
even with parametized constructor k
public Bar2 ()
{
i = 10001; //makes no difference
}
public Bar2(int k) :base(k) //i = k still not called, ever!
[for .ToString()]
{
i = k;

}
public int get_i()
{
int eye = i;
return eye;
}

public override string ToString()
{

return ("Hi!!" + i.ToString()); //
}
}

////////////////////////////////

/*

// in static void Main(string[] args) ---

Bar1 bar1 = new Bar1(432); //doesn't do what you think
Bar2 bar2 = new Bar2(201); //""
Console.WriteLine("Bar2 int i is: {0}", bar2.get_i());

*/



/* OUTPUT

!Foo base loves explicit initialization outside of constructor always!
Hi321
Bar1's i is: 432
!Foo base loves explicit initialization outside of constructor always!
Hi!!0
Bar2 int i is: 201
Press any key to continue . . .


*/
 
U

UL-Tomten

A good part of an hour wasted!

I assume by "wasted", you mean "drunk".
wall, and thinking I've gone crazy, I've concluded that this program
does not appear to work as expected due to an optical illusion [...]

It works precisely as expected. It's just your expectations that are
inconsistent with the outcome.

I've modified the sample slightly to use only explicitly defined
methods (below). To only place in which ToString() is now used is when
printin' an int, and I used ToString() explicitly for clarity. And
just so we are talking about the same thing: the only interesting
thing in this code is the fact that a base constructor calls a virtual
(and in this case, overridden) function. (And the only interesting
thing about that, in turn, is that it illustrates the not-so-obvious
difference between initializing a variable in the declaration and
doing it in the constructor, into which the compiler will move it
anyway.) The rest is just there to make that obvious.

But don't take my word for it. If you compile the below (or the
original example I found on the Internets) and look at the compiled
IL, you can see exactly what's going on, and why.

class Program {
static void Main(string[] args) {
new Bar1();
new Bar2();
}
}
class Foo {
public Foo() {
Console.WriteLine(this.VirtualOrOverridden());
}
public virtual string VirtualOrOverridden() {
return "Foo";
}
}
class Bar1 : Foo {
private int i;
public Bar1() {
i = 123;
}
public override string VirtualOrOverridden() {
return i.ToString();
}
}
class Bar2 : Foo {
private int i = 123;
public Bar2() {
}
public override string VirtualOrOverridden() {
return i.ToString();
}
}
 
R

raylopez99

A good part of an hour wasted!

I assume by "wasted", you mean "drunk".
wall, and thinking I've gone crazy, I've concluded that this program
does not appear to work as expected due to an optical illusion [...]

It works precisely as expected. It's just your expectations that are
inconsistent with the outcome.

I've modified the sample slightly to use only explicitly defined
methods (below). To only place in which ToString() is now used is when
printin' an int, and I used ToString() explicitly for clarity. And
just so we are talking about the same thing: the only interesting
thing in this code is the fact that a base constructor calls a virtual
(and in this case, overridden) function. (And the only interesting
thing about that, in turn, is that it illustrates the not-so-obvious
difference between initializing a variable in the declaration and
doing it in the constructor, into which the compiler will move it
anyway.) The rest is just there to make that obvious.

UL-Tomten--thanks for this obscure example, which to me only
illustrates that ToString() is messed up.

Since this is Monday I get the last word (you can only post on
weekends).

I'm sure the "IL" complier does indeed exactly what is expected of it--
but again, from a rapid programmer hobbiest like myself, I don't
really care about 'theory' but practice. This example is just an
obscure outlier unless I can see another class of examples not using
ToString(), which I think is the 'key' to this example working as it
does.

RL
 
J

Jon Skeet [C# MVP]

UL-Tomten--thanks for this obscure example, which to me only
illustrates that ToString() is messed up.

What *exactly* do you believe is "messed up"?

Jon
 
R

raylopez99

What *exactly* do you believe is "messed up"?

Jon

See my code as posted--I expected when .ToString was run for the
'virtual' keyword to mean that the derived class values of the
integers in the constructor be used, rather than the value of integer
i that was outside the constructor, as actually occurred.

To give but one example:

private int i=321; //*1* //overrides the normal constructor
always (at least for ToString)
// private int i; //*2* // gives zero, i=123; never called

public Bar1() //public Bar1 ():base() //same thing, not what
you think
{
i = 123;
[deletions]

In the above, depending on whether you comment out lines "//*1*" or "//
*2*", the output of ToString is either 321 for i, or zero for i, but
never i=123; This is true even if you parametrize the constructor and
explicitly call the base parametized (see "base(k)"). But, this seems
to work only for ToString--and from what I've seen most virtual
overridden functions in C# don't work this way (otherwise you would
have a real mess). If you look in textbook example (at least the one
textbook I have from 7 year ago on C#), the virtual functions in C#
work nearly the same as in C++ (but with alot more confusing
keywords: essentially you have to either hide or override the base
class, with one other keyword that escapes me at the moment).

For me, the original example was counterintutive. But I'm sure if you
study the intermediate assembly language and step through it line by
line, you convince yourself otherwise... just not what I would
expect.

RL
 
M

Marc Gravell

As a general rule, calling a virtual function in a constructor chain
simply isn't a smart thing to do - none of the classes can know
whether any protected / virtual etc methods will work as expected. I
believe that FxCop will raise a warning about this.

For the specific case, I'm not sure I understand your code well enough
(it isn't written in a very easy-to-follow way). However, I'm not
convinced that your code shows anything unexpected...

Marc
 
J

Jon Skeet [C# MVP]

See my code as posted--I expected when .ToString was run for the
'virtual' keyword to mean that the derived class values of the
integers in the constructor be used, rather than the value of integer
i that was outside the constructor, as actually occurred.

That's nothing to do with ToString though - it's the order in which
construction occurs, that's all. The base constructor is called before
any of the code within the derived class constructor. It's not that
"i=123" is never executed - it's just executed *after* the base
constructor code has completed.

Nothing is messed up, there's nothing special about ToString - you
just weren't expecting the well-documented order of constructor
execution.
For me, the original example was counterintutive. But I'm sure if you
study the intermediate assembly language and step through it line by
line, you convince yourself otherwise... just not what I would
expect.

You don't need to study the IL - you just need to read the C# spec.

Jon
 
R

raylopez99

As a general rule, calling a virtual function in a constructor chain
simply isn't a smart thing to do - none of the classes can know
whether any protected / virtual etc methods will work as expected. I
believe that FxCop will raise a warning about this.


Thanks for this clarification--I've noted not not call virtual
functions within the constructor, for future reference.

RL
 
J

Jon Skeet [C# MVP]

raylopez99 said:
Thanks for this clarification--I've noted not not call virtual
functions within the constructor, for future reference.

There are times when it's appropriate to do so, but they are relatively
rare and should usually *only* be called within the constructor.
Careful documentation is the important point here, IMO.
 

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