공개적으로 변경 가능한 필드 또는 속성을 가진 구조는 악하지 않습니다.
.net이 그렇지 않은 메소드와 구별 할 수있는 방법을 제공하지 않기 때문에 "this"를 변경하는 구조 메소드 (특성 설정자와는 구별됨)는 다소 악의적입니다. "this"를 변경하지 않는 구조 메소드는 방어 적 복사가 필요없는 읽기 전용 구조체에서도 호출 할 수 있어야합니다. "this"를 변경하는 메소드는 읽기 전용 구조체에서 호출 할 수 없어야합니다. .net은 읽기 전용 구조체에서 "this"가 호출되는 것을 수정하지 않는 구조체 메소드를 금지하고 싶지 않지만 읽기 전용 구조체의 변경을 허용하지 않으려면 구조체를 읽기 전용으로 복사합니다. 두 세계에서 최악의 상황이 될 수 있습니다.
그러나 읽기 전용 컨텍스트에서 자체 변경 메소드를 처리하는 데 문제가 있음에도 불구하고 변경 가능한 구조체는 종종 변경 가능한 클래스 유형보다 훨씬 우수한 의미를 제공합니다. 다음 세 가지 메소드 서명을 고려하십시오.
struct PointyStruct {public int x, y, z;};
PointyClass 클래스 {public int x, y, z;};
void Method1 (PointyStruct foo);
void Method2 (참조 PointyStruct foo);
void Method3 (PointyClass foo);
각 방법에 대해 다음 질문에 답하십시오.
- 메소드가 "안전하지 않은"코드를 사용하지 않는다고 가정하면 foo를 수정할 수 있습니까?
- 메소드가 호출되기 전에 'foo'에 대한 외부 참조가 없으면 외부 참조가 존재할 수 있습니까?
대답:
질문 1 :
Method1()
: 아니오 (명확한 의도)
Method2()
: 예 (명확한 의도)
Method3()
: 예 (불확실한 의도)
질문 2 :
Method1()
: 아니오
Method2()
: 아니오 ( 아니요 안전하지 않은 경우)
Method3()
: 예
Method1은 foo를 수정할 수 없으며 참조를 얻지 않습니다. Method2는 foo에 대한 짧은 참조를 가져옵니다. foo는 반환 될 때까지 순서에 상관없이 foo 필드를 여러 번 수정할 수 있지만 해당 참조를 유지할 수는 없습니다. 안전하지 않은 코드를 사용하지 않으면 Method2가 리턴되기 전에 'foo'참조로 작성된 모든 사본이 사라집니다. Method2는 Method2와 달리 foo에 대해 무차별 적으로 공유 할 수있는 참조를 얻습니다. foo를 전혀 변경하지 않거나 foo를 변경 한 다음 반환하거나 다른 스레드에 대한 foo에 대한 참조를 제공하여 나중에 임의의 방식으로 임의의 방식으로 변경시킬 수 있습니다.
구조의 배열은 훌륭한 의미를 제공합니다. Rectangle 유형의 RectArray [500]이 주어진 경우, 예를 들어 요소 123을 요소 456에 복사 한 다음 나중에 요소 456을 방해하지 않고 요소 123의 너비를 555로 설정하는 방법이 명확하고 분명합니다. "RectArray [432] = RectArray [321 ]; ...; RectArray [123] .Width = 555; ". Rectangle이 Width라는 정수 필드를 가진 구조체라는 것을 알면 위의 문장에 대해 모두 알아야 할 것입니다.
이제 RectClass가 Rectangle과 동일한 필드를 가진 클래스이고 RectClass 유형의 RectClassArray [500]에서 동일한 작업을 수행하려고한다고 가정하십시오. 아마도 배열은 변경 가능한 RectClass 객체에 대해 사전 초기화 된 500 개의 불변 참조를 보유해야합니다. 이 경우 올바른 코드는 "RectClassArray [321] .SetBounds (RectClassArray [456]); ...; RectClassArray [321] .X = 555;"와 같은 코드입니다. 아마도 배열은 변경되지 않을 인스턴스를 보유한다고 가정하므로 적절한 코드는 "RectClassArray [321] = RectClassArray [456]; ...; RectClassArray [321] = New RectClass (RectClassArray [321) ]); RectClassArray [321] .X = 555; " 무엇을 해야하는지 알기 위해서는 RectClass에 대해 더 많이 알아야합니다 (예 : 복사 생성자, copy-from 메소드 등을 지원합니까). ) 및 배열의 의도 된 사용법. 구조체를 사용하는 것만 큼 깨끗한 곳은 없습니다.
확실히 배열 이외의 컨테이너 클래스가 구조체 배열의 깨끗한 의미를 제공하는 좋은 방법은 없습니다. 컬렉션으로 문자열을 색인화하기를 원한다면 가장 좋은 방법은 색인에 대한 문자열, 일반 매개 변수 및 전달되는 대리자를 허용하는 일반 "ActOnItem"메소드를 제공하는 것입니다. 제네릭 매개 변수와 컬렉션 항목을 모두 참조하십시오. 그것은 구조체 배열과 거의 동일한 의미를 허용하지만 vb.net 및 C # 사람들이 멋진 구문을 제공하도록 설득 할 수 없다면 코드가 성능이 우수하더라도 (일반 매개 변수를 전달해도 코드가 어색해 보입니다) 정적 대리자를 사용할 수 있으며 임시 클래스 인스턴스를 만들 필요가 없습니다.
개인적으로, 나는 증오 Eric Lippert et al. 가변 값 유형과 관련하여 분출합니다. 그들은 모든 곳에서 사용되는 무차별 참조 유형보다 훨씬 더 명확한 의미를 제공합니다. .net의 값 유형 지원에 대한 일부 제한 사항에도 불구하고 가변 값 유형이 다른 유형의 엔티티보다 더 적합한 경우가 많이 있습니다.
int
,bool
s를 주장하는 것과 같 으며 다른 모든 값 유형은 악입니다. 변경 가능성과 불변성에 대한 경우가 있습니다. 이러한 경우는 메모리 할당 / 공유 유형이 아니라 데이터의 역할에 달려 있습니다.