새 객체를 만들거나 모든 속성을 재설정 하시겠습니까?


29
 public class MyClass
    {
        public object Prop1 { get; set; }

        public object Prop2 { get; set; }

        public object Prop3 { get; set; }
    }

객체 myObjectMyClass있고 속성을 재설정해야 한다고 가정 합니다. 새 객체를 만들거나 각 속성을 다시 할당하는 것이 더 낫습니까? 이전 인스턴스에서 추가로 사용하지 않는다고 가정하십시오.

myObject = new MyClass();

또는

myObject.Prop1 = null;
myObject.Prop2 = null;
myObject.Prop3 = null;


14
문맥이 없으면 실제로 대답 할 수 없습니다.
코드 InChaos

2
@CodesInChaos입니다. 새로운 객체 생성이 바람직하지 않은 특정 예 : 객체 풀링 및 GC 처리를위한 할당 최소화를 시도합니다.
XNargaHuntress 2016 년

@ XGundam05 그러나 그때도 OP에서 제안 된이 기술이 그것을 다루는 적절한 방법 일 가능성은 거의 없습니다
Ben Aaronson

2
Suppose I have an object myObject of MyClass and I need to reset its properties-객체의 속성을 재설정해야하거나 문제 도메인을 모델링하는 것이 유용한 경우 reset()MyClass에 대한 메소드를 작성하십시오 . 아래 HarrisonPaine의 답변 참조
Brandin

답변:


49

새 객체를 인스턴스화하는 것이 항상 좋습니다. 그런 다음 속성 (생성자)을 초기화하고 쉽게 업데이트 할 수있는 한 곳이 있습니다.

클래스에 새 속성을 추가한다고 가정하면 모든 속성을 다시 초기화하는 새 메서드를 추가하는 것보다 생성자를 업데이트하는 것이 좋습니다.

이제 객체를 재사용하고 싶을 때가 있습니다. 재 초기화하는 데 비용이 많이 들고 유지하려는 경우가 있습니다. 그러나 이것은 더 전문적이며 다른 모든 속성을 다시 초기화하는 특별한 방법이 있습니다. 이 상황에서도 때때로 새 객체를 만들고 싶을 것입니다.


6
가능한 세 번째 옵션 : myObject = new MyClass(oldObject);. 비록 이것이 새로운 인스턴스에서 원본 객체의 정확한 사본을 의미합니다.
AmazingDreams

new MyClass(oldObject)초기화가 비싼 경우에 가장 적합한 솔루션 이라고 생각합니다 .
rickcnagy 2016 년

8
복사 생성자는 더 많은 C ++ 스타일입니다. .NET은 정확한 사본 인 새 인스턴스를 반환하는 Clone () 메서드를 선호하는 것 같습니다.
Eric

2
컨스트럭터는 public Initialize () 메소드를 호출하는 것 외에는 아무것도 할 수 없으므로 "새"신선한 객체를 효과적으로 생성하기 위해 어느 시점에서든 호출 할 수있는 단일 초기화 지점이 여전히 있습니다. 객체 풀에서 사용하고 성능을 위해 재사용 할 수있는 객체에 IInitialize 인터페이스와 같은 라이브러리를 사용했습니다.
Chad Schouggins

16

당신은 확실히 새로운 개체를 만드는 것을 선호한다 방대한 사례의 대부분을. 모든 속성을 재 할당 할 때 발생하는 문제 :

  • 모든 속성에 공개 세터가 필요하며 제공 할 수있는 캡슐화 수준이 크게 제한됩니다.
  • 이전 인스턴스에 추가로 사용되는지 여부를 알면 이전 인스턴스가 사용되는 모든 곳을 알아야합니다. 클래스 A와 클래스 B가 모두 클래스의 인스턴스를 통과 하면C 로 전달되면 동일한 인스턴스가 전달되는지 여부와 다른 인스턴스가 여전히 사용 중인지 여부를 알아야합니다. 이것은 다른 이유가없는 클래스를 단단히 결합합니다.
  • gbjbaanb가 지적한 것처럼 반복 코드로 이어집니다. 생성자에 매개 변수를 추가하면 생성자를 호출하는 모든 곳에서 컴파일이 실패하고 스팟이 없어 질 위험이 없습니다. 공개 속성 만 추가하면 개체가 "재설정"된 모든 위치를 수동으로 찾아 업데이트해야합니다.
  • 복잡성을 증가시킵니다. 루프에서 클래스의 인스턴스를 만들고 사용한다고 상상해보십시오. 메소드를 사용하는 경우 이제 루프를 통해 처음 또는 루프가 시작되기 전에 별도의 초기화를 수행해야합니다. 이 두 가지 초기화 방법을 지원하기 위해 작성해야하는 추가 코드가 있습니다.
  • 클래스가 자신을 잘못된 상태로 보호 할 수 없음을 의미합니다. 당신이 쓴 상상Fraction분자와 분모 클래스 클래스가 항상 줄어든다고 (예 : 분자와 분모의 gcd가 1 임). 사람들이 분자와 분모를 공개적으로 설정하도록 허용하려는 경우, 유효하지 않은 상태를 통해 유효한 상태에서 다른 상태로 전환 할 수 있기 때문에 훌륭하게 수행 할 수 없습니다. 예 : 1/2 (유효한)-> 2/2 (유효하지 않은)-> 2/3 (유효한).
  • 작업중 인 언어에 대해 관용적이지 않아 코드를 유지하는 사람의인지 마찰이 증가합니다.

이것들은 모두 상당히 중요한 문제입니다. 그리고 당신이 만든 추가 작업에 대한 대가로 얻는 것은 ... 아무것도 아닙니다. 일반적으로 객체 인스턴스를 만드는 것은 매우 저렴하므로 성능상의 이점은 거의 무시할 수 있습니다.

다른 답변에서 언급했듯이, 성과가 관련 문제 일 수있는 유일한 시간은 수업에서 건설에 상당히 비싼 작업을 수행하는 경우입니다. 그러나이 경우 에도이 기술이 작동하려면 재설정하는 속성과 비싼 부분을 분리해야하므로 플라이급 패턴 또는 이와 유사한 것을 사용할 수 있습니다 .


부수적으로, 위의 문제 중 일부 는 setter를 사용하지 않고 대신에public Reset 클래스에서 생성자와 동일한 매개 변수를 취하는 메서드를 . 어떤 이유로 든이 재설정 경로를 내려 가고 싶을 경우에는 훨씬 더 나은 방법 일 것입니다.

그럼에도 불구하고, 위에서 언급하지 않은 점과 함께 추가 복잡성과 반복은 여전히 ​​존재하지 않는 이익에 대해 무게를 측정 할 때 그것을 설득하는 데 매우 설득력있는 주장입니다.


새 객체를 만드는 것이 아니라 재설정하는 데 매우 중요한 사용 사례는 실제로 객체를 재설정하는 것입니다. IE. 객체를 가리키는 다른 클래스가 재설정 후 새로운 객체를 볼 수있게하려면
Taemyr

@Taemyr 아마도 OP는 질문에서 그것을 명백히 배제합니다
Ben Aaronson

9

매우 일반적인 예를 들자면 말하기가 어렵습니다. 도메인의 경우 "속성 재설정"이 의미 상 의미가있는 경우 클래스의 소비자에게 전화하는 것이 더 합리적입니다.

MyObject.Reset(); // Sets all necessary properties to null

보다

MyObject = new MyClass();

나는 당신의 클래스 콜 소비자를 요구하지 않을 것입니다

MyObject.Prop1 = null;
MyObject.Prop2 = null; // and so on

클래스가 재설정 할 수있는 것을 나타내는 경우 Reset()생성자를 호출하거나 속성을 수동으로 설정하지 않고 메소드를 통해 해당 기능을 노출해야 합니다.


5

Harrison Paine과 Brandin이 제안한 것처럼 동일한 객체를 재사용하고 Reset 메소드에서 속성 초기화를 인수 분해합니다.

public class MyClass
{
    public MyClass() { this.Reset() }

    public void Reset() {
        this.Prop1 = whatever
        this.Prop2 = you name it
        this.Prop3 = oh yeah
    }

    public object Prop1 { get; set; }

    public object Prop2 { get; set; }

    public object Prop3 { get; set; }
}

정확히 내가 대답하고 싶었던 것. 이것은 두 세계의 최고입니다-그리고 유스 케이스에 따라 유일하게 가능한 선택 (인스턴스 풀링)
Falco

2

클래스의 의도 된 사용 패턴이 단일 소유자가 각 인스턴스에 대한 참조를 유지하는 것이라면 다른 코드는 참조의 사본을 유지하지 않으며 소유자가 여러 번 " 빈 인스턴스를 채우고 일시적으로 사용하고 다시는 필요하지 않습니다 (공통 클래스가 이러한 기준을 충족 할 것임 StringBuilder). 새로운 조건. 대안으로 수백 개의 인스턴스 만 생성하면되지만 수백만 또는 수십억 개의 객체 인스턴스를 생성하는 비용이 추가 될 수 있다면 이러한 최적화는 그다지 가치가 없을 것입니다.

관련 참고 사항에서 객체의 데이터를 반환 해야하는 메소드에 사용할 수있는 몇 가지 패턴이 있습니다.

  1. 메소드는 새로운 객체를 생성합니다. 참조를 반환합니다.

  2. 메소드는 변경 가능한 오브젝트에 대한 참조를 승인하고 채 웁니다.

  3. 메소드는 참조 유형 변수를 ref매개 변수로 승인하고 적합한 경우 기존 오브젝트를 사용하거나 새 오브젝트를 식별하도록 변수를 변경합니다.

첫 번째 방법은 의미 상 가장 쉬운 방법입니다. 두 번째는 호출 측에서 약간 어색하지만 호출자가 자주 하나의 개체를 만들어 수천 번 사용할 수 있으면 성능이 향상 될 수 있습니다. 세 번째 방법은 의미 상 약간 어색하지만 메서드가 배열에서 데이터를 반환해야하고 호출자가 필요한 배열 크기를 알지 못하는 경우 도움이 될 수 있습니다. 호출 코드가 배열에 대한 유일한 참조를 보유하는 경우 더 큰 배열에 대한 참조로 해당 참조를 다시 작성하는 것은 의미 적으로 배열을 더 크게 만드는 것과 의미 적으로 동일합니다 (이는 원하는 동작으로 의미 론적으로). List<T>많은 경우에 수동 크기 조정 배열을 사용하는 것보다 사용하는 것이 좋을 수도 있지만 , 구조 배열은 구조 목록보다 의미와 성능이 우수합니다.


1

새로운 객체 생성을 선호하는 사람들은 대부분 가비지 수집 (GC)이라는 중요한 시나리오가 빠져 있다고 생각합니다. GC는 많은 객체를 만드는 응용 프로그램 (게임이나 과학 응용 프로그램)에서 실제 성능을 발휘할 수 있습니다.

내부 노드에 함수 노드 (ADD, SUB, MUL, DIV)가 있고 리프 노드가 터미널 노드 (X, e, PI) 인 수학적 표현을 나타내는 표현식 트리가 있다고 가정하겠습니다. 내 노드 클래스에 Evaluate () 메서드가 있으면 자식을 재귀 적으로 호출하고 데이터 노드를 통해 데이터를 수집합니다. 최소한 모든 리프 노드는 Data 객체를 생성해야하며 최종 값이 평가 될 때까지 트리 위로 올라가 재사용 할 수 있습니다.

이제 수천 개의 나무가 있는데 루프에서 평가한다고 가정 해 봅시다. 이러한 모든 Data 객체는 GC를 트리거하고 성능 저하를 유발합니다 (내 앱에서 일부 실행에서 최대 40 %의 CPU 사용률 손실-데이터를 얻기 위해 프로파일 러를 실행했습니다).

가능한 해결책? 해당 데이터 객체를 재사용하고 사용을 마친 후에 .Reset ()을 호출하십시오. 리프 노드는 더 이상 'new Data ()'를 호출하지 않으며 객체의 수명주기를 처리하는 일부 Factory 메소드를 호출합니다.

이 문제에 부딪친 응용 프로그램이 있기 때문에 이것을 알고 해결했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.