구성 전에 개체 참조 보내기
응용 프로그램 중 하나에서 다음 코드를 보았습니다.
public class First()
{
private Second _second;
public First()
{
_second = new Second(this);
// Doing some other initialization stuff,
}
}
public class Second
{
public Second(First f)
{
}
}
에서 First()생성자, 우리가 클래스의 참조를 보내는 것이 나쁘지 않다 First() 전에 완전히 구성되어? 제어 논리가 생성자를 떠나면 개체가 완전히 생성된다고 생각합니다.
아니면 괜찮습니까?
내 질문은 First () 생성자에서 완전히 생성되기 전에 First () 클래스의 참조를 보내는 것이 나쁘지 않습니까?
약간. 그것은 수 확실히 문제.
Second생성자 가 나중에 사용하기 위해 참조 만 유지 한다면 그렇게 나쁘지 않습니다. 반면에 Second생성자가 다음으로 다시 호출하는 경우 First:
public Second(First f)
{
f.DoSomethingUsingState();
}
... 그리고 주가 아직 설정되지 않았다면 그것은 물론 매우 나쁜 일이 될 것입니다. 당신이 호출 할 경우 가상 의 방법을 First그것은 더 악화 될 수 있습니다 - 당신도 실행할 수있는 기회가 없었습니다 일부 코드로 호출 끝낼 수 있는 (그 변수 초기화가 실행 된 것입니다 있지만) 아직 생성자 몸을.
특히 readonly필드는 먼저 하나의 값으로 표시되고 나중에 다른 값으로 표시 될 수 있습니다.
나는 이것에 대해 얼마 전에 블로그에 올렸 는데 더 많은 정보를 제공 할 수있을 것이다.
물론, 이런 종류의 일을 하지 않으면 상호 참조 불변 객체 두 개를 만드는 것은 꽤 어렵습니다 ...
이 패턴이 발생하면 대신 다음과 같이 리팩토링 할 수 있는지 확인할 수 있습니다.
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 into the constructor implies a kind of tight coupling between the two classes, as First has to trust that Second knows what it is doing and won't try to rely on the uninitialized state of First. This kind of strong coupling is more appropriate when Second is a private nested subclass (and hence a clear implementation detail) or possibly when it's an internal class.
The answer is, it depends. Generally, though, this would be considered a bad idea due to the potential consequences.
More specifically, though, as long as Second doesn't actually use anything from First before it is constructed, then you should be okay. If you can't guarantee that somehow though, you could definitely run into problems.
Yes it is somewhat bad. It is possible to do things to the fields of First before it is fully initialized, which would cause undesired or undefined behavior.
The same thing happens when you call a virtual method from your constructor.
In contrast to e.g. C++, CLR has no notion of fully constructed or incompletely constructed objects. As soon as the memory allocator returns a zeroed object and before the constructor runs, it is ready to use (from the CLR's point of view). It has its final type, calls to virtual methods invoke the most derived override etc. You can use this in constructor's body, call virtual methods etc. This may indeed cause problems with order of initialization, but there is nothing in CLR to prevent them.
It is true that this might lead to problems as you described. Therefore, it is generally adviseable to run commands such as _second = new Second(this); only after the other initialization stuff implied by your comment.
Quite sometimes, this pattern is the only solution for storing reciprocal references between two objects. In many cases, however, this occurs in a way that the class receiving the possibly-not-fully-initialized instance is tightly coupled to the referenced class (e.g. written by the same author; part of the same application; or a nested class, possibly private). In such cases, negative effects can be avoided as the author of Second knows (or has possibly even written) the internals of First.
It depends on scenario, but it could lead to difficult to predict behavior. If Second does anything with First in the constructor, that behavior may become ill-defined once you alter the constructor of First. Additional constructor guidance also suggests that you shouldn't call virtual or abstract methods (on the constructed class) in a constructor, because it can lead to similar consequences where behavior may be difficult to reason about.
The answer to this question depends on the nature of the relationship between First and Second.
Think about what sort of object might be composed of another object, which is itself composed of (or requires for its initialization) the object of type First. In situations like this, you should be wary of creating object graphs with cycles.
Nevertheless, there are plenty of legitimate situations in which a cycle should occur in an object graph. If First relies on the state of Second to perform its initialization, then you should keep the method as is and that is generally okay. If Second relies on the state of First to perform its own initialization, then you should probably rearrange the constructor as such:
public First()
{
// Doing some other initialization stuff,
_second = new Second(this);
}
If both of the preceding statements are true (Second depends on the state of First, and First depends on the state of Second), then you should almost certainly revisit your design, and figure out more precisely the nature of the relationship between First and Second. (Maybe there should be some object Third that contains a reference to both First and Second, and the relationship between the latter two should be arbitrated by Third.)
참고URL : https://stackoverflow.com/questions/11784878/sending-reference-of-object-before-its-construction
'Nice programing' 카테고리의 다른 글
| 정적 라이브러리 디버그 기호 (0) | 2020.11.24 |
|---|---|
| 자바 스크립트에서 유효하지 않은 필드를 표시 할 수 있습니까? (0) | 2020.11.24 |
| 장고 뷰에 대한 단위 테스트를 작성하는 방법은 무엇입니까? (0) | 2020.11.24 |
| '네임 스페이스'이지만 '유형'처럼 사용됩니다. (0) | 2020.11.24 |
| dplyr 조건부 값으로 변경 (0) | 2020.11.24 |