Submitting a site reference before construction

I saw the following code in one of our applications:

public class First() { private Second _second; public First() { _second = new Second(this); // Doing some other initialization stuff, } } public class Second { public Second(First f) { } } 

Is it not bad in the First() constructor that we send a reference to the First() class before it is completely built? I think that the object is completely built only after the control logic leaves the constructor.

Or is this normal?

+63
constructor reference c #
Aug 02 '12 at 20:00
source share
8 answers

My question is: is it not bad in the First () constructor that we send a link to the First () class BEFORE it is completely built?

Some. This can be a problem, of course.

If the Second constructor just keeps a reference for later use, it's not so bad. If, on the other hand, the Second constructor accesses First :

 public Second(First f) { f.DoSomethingUsingState(); } 

... and the condition is not yet configured, then this, of course, will be a very bad thing. If you call the virtual method on First , then it can be even worse - you can end up calling code that did not even have the ability to run any of its constructor body (although its variable initializers will be executed).

In particular, readonly fields are visible first with one value and then with another ...

I wrote about this some time ago, which may provide additional information.

Of course, without doing this kind of thing, itโ€™s quite difficult to create two mutually referenced immutable objects ...

+70
Aug 02 2018-12-12T00:
source share

If you come across this template, you can check if it can be reorganized into it:

 public class First() { private Second _second; public First() { _second = new Second(this); // Doing some other initialization stuff, } private class Second { public Second(First f) { } } } 

Passing the dependency to the constructor implies some tough connection between the two classes, since First must assume that Second knows what it is doing and will not try to rely on the uninitialized state of First. Such a strong connection is more suitable if Second is a private nested subclass (and therefore a clear implementation detail) or, possibly, when it is an inner class.

+17
Aug 02 2018-12-12T00:
source share

Answer: it depends. In general, however, this would be considered a bad idea because of the possible consequences.

In particular, although as long as Second does not actually use anything from First before creating it, then you should be fine. If you cannot guarantee that one way or another, you are likely to run into problems.

+11
Aug 02 2018-12-12T00:
source share

Yes, this is a little bad. Before it is fully initialized, it is possible to do something in the First , which will lead to unwanted or undefined behavior.

The same thing happens when you call a virtual method from your constructor.

+4
Aug 02 2018-12-12T00:
source share

Unlike, for example, C ++, the CLR does not have the concept of fully constructed or incompletely constructed objects. As soon as the memory allocator returns an object with a zero value and before the constructor starts, it is ready for use (from the CLR point of view). It has its final type, calls to virtual methods cause the most derived overrides, etc. You can use this in the constructor body, call virtual methods, etc. This can actually cause problems with the initialization order, but there is nothing in the CLR that could prevent them.

+3
Aug 02 '12 at 20:10
source share

True, this can lead to the problems described by you. Therefore, it is usually recommended to run commands such as _second = new Second(this); , only after you have added other initialization material indicated by your comment.

Quite often, this template is the only solution for storing reciprocal links between two objects. However, in many cases, this happens so that the class receiving the possibly not fully initialized instance is closely related to the reference class (for example, written by the same author, part of the same application, or a nested class, possibly private). In such cases, negative effects can be avoided, since the author of Second knows (or perhaps even wrote down) the insides of First .

+1
Aug 02 2018-12-12T00:
source share

It depends on the scenario, but it can lead to complex prediction of behavior. If Second does something with First in the constructor, this behavior may become fuzzy if you change the constructor of First . The constructorโ€™s additional guidance also suggests that you should not invoke virtual or abstract methods (on the constructed class) in the constructor, because this can lead to similar consequences when the behavior can be difficult to explain.

+1
Aug 02 '12 at 20:10
source share

The answer to this question depends on the nature of the relationship between First and Second .

Think about which object can consist of another object, which itself consists of (or requires for its initialization) an object of type First . In such situations, you should be wary of creating graphs of objects with loops.

However, there are many legitimate situations in which a cycle must occur in a graph of objects. If First relies on the Second state to perform its initialization, you should keep the method as it is, and that is generally normal. If Second relies on the state of First to do its own initialization, then you should probably rebuild the constructor as such:

  public First() { // Doing some other initialization stuff, _second = new Second(this); } 

If both of the previous statements are true ( Second depends on the state of First , and First depends on the state of Second ), you should almost certainly revise your design and find out more precisely the nature of the relationship between First and Second . (Maybe there should be some Third object that contains a link to both First and Second , and the connection between the last two should be resolved using Third .)

+1
Aug 02 '12 at 20:13
source share



All Articles