C #의 "const correctness"


79

const-correctness의 요점은 사용자가 변경하거나 삭제할 수없는 인스턴스보기를 제공 할 수 있다는 것입니다. 컴파일러는 const 함수 내에서 constness를 중단하거나 const 객체의 상수가 아닌 함수를 사용하려고 할 때이를 지적하여이를 지원합니다. 따라서 const 접근 방식을 복사하지 않고 동일한 끝을 가진 C #에서 사용할 수있는 방법론이 있습니까?

나는 불변성을 알고 있지만 이름을 지정하기 위해 컨테이너 객체에 실제로 적용되지는 않지만 하나의 예입니다.



그렇다면 const_castC #으로 구현하는 것은 어떻습니까?
kerem

답변:


64

나는이 문제를 자주 접했고 결국 인터페이스를 사용하게되었다.

나는 C #이 어떤 형태 나 C ++의 진화라는 생각을 버리는 것이 중요하다고 생각합니다. 거의 동일한 구문을 공유하는 두 개의 다른 언어입니다.

저는 보통 클래스의 읽기 전용 뷰를 정의하여 C #에서 'const correctness'를 표현합니다.

public interface IReadOnlyCustomer
{
    String Name { get; }
    int Age { get; }
}

public class Customer : IReadOnlyCustomer
{
    private string m_name;
    private int m_age;

    public string Name
    {
        get { return m_name; }
        set { m_name = value; }
    }

    public int Age
    {
        get { return m_age; }
        set { m_age = value; }
    }
}

12
물론입니다.하지만 필드 중 하나가 목록이거나 리치 유형이면 어떻게 될까요? 솔루션은 매우 빠르게 복잡해집니다.
Matt Cruikshank

12
@Trap : 그것이 질문의 요점입니다. 내부 컬렉션을 반환하는 것은 외부 세계가 const를 사용하여 해결되는 C ++에서 내부를 수정할 수 있기 때문에 나쁜 습관입니다. 요소)이므로 안전합니다 (그리고 일반적인 관용구). 외부 코드가 내부를 변경하지 않도록 인터페이스 또는 기타 트릭을 해결할 필요가 없습니다.
David Rodríguez-dribeas

9
@Trap, 저는이 메커니즘이 경험이 있든 없든 개발자의 오류를 감지하는 것을 포함하는 개발 보조 도구라는 데 동의합니다. 읽기 전용 인터페이스를 작성해야하는 것이 여러 가지 측면에서 더 나은 솔루션이라는 데 동의하지 않습니다. 첫 번째 요점은 C ++로 클래스를 작성할 때마다 const별도의 인터페이스를 정의하고 런타임 디스패치를 ​​요구하는 추가 비용없이 선언 된 멤버의 하위 집합 인 상수 인터페이스를 암시 적으로 정의 한다는 것입니다. 즉,이 언어는 컴파일 타임 const 인터페이스를 구현하는 간단한 방법을 제공합니다.
David Rodríguez-dribeas

10
const-ness 디자인의 일부이며 외부 const 인터페이스를 작성하는 것처럼 명확하게 의도를 선언 한다는 점에 유의하는 것이 중요합니다 . 또한 const 인터페이스를 제공하는 것은 수동으로 처리해야하는 경우 복잡한 작업이 될 수 있으며 복합 유형에있는 클래스 수만큼 인터페이스를 작성해야 할 수도 있습니다. 그것은 우리를 당신의 마지막 센티스로 데려갑니다 : 'const를 추가하는 것을 잊었 기 때문에 문제를 해결하라'. const모든 클래스에 대해 읽기 전용 인터페이스를 작성하는 것보다 모든 곳에 추가하는 것이 더 쉽습니다 (개발 비용이 적음).
David Rodríguez-dribeas

9
내가 C #이 나왔을 때 정말 좋아했던 이유 중 하나는 Java처럼 C ++의 모든 실용적인 기능을 버리지 않았기 때문입니다. Java는 인터페이스로 모든 것을 시도했지만 재앙이었습니다. 증거는 푸딩에 있습니다. 시간이 지남에 따라 원래 이단으로 비난되었던 많은 기능이 Java에 "다시"추가되었습니다. 인터페이스 기반 디자인은 그 자리를 차지하지만 극단적 인 경우 프로그램의 아키텍처를 불필요하게 복잡하게 만들 수 있습니다. 결국 상용구 코드를 작성하는 데 더 많은 시간을 소비하고 유용한 작업을 수행하는 데 더 적은 시간을 소비하게됩니다.
kgriffs 2011

29

const-craziness (또는 함수형 프로그래밍 용어의 순수성)의 이점을 얻으려면 c #의 String 클래스와 마찬가지로 변경 불가능한 방식으로 클래스를 디자인해야합니다.

이 접근 방식은 개체를 읽기 전용으로 표시하는 것보다 훨씬 낫습니다. 불변 클래스를 사용하면 멀티 태스킹 환경에서 데이터를 쉽게 전달할 수 있기 때문입니다.


8
하지만 불변성은 실제로 복잡한 객체로 확장되지 않습니다. 그렇지 않습니까?
tenpn

8
나는 당신의 객체가 너무 복잡해서 불변성이 불가능하다면 리팩토링에 좋은 후보가 될 것이라고 주장합니다.
Jim Burger

2
나는 이것이 그룹의 최고라고 생각합니다. 변경 불가능한 객체는 너무 드물게 사용됩니다.

3
그뿐만 아니라 개체를 변경하고 싶지만 (개체가 변경됩니다!) 대부분의 경우 읽기 전용보기를 제공하는 경우도 있습니다. 불변 객체는 변경해야 할 때 (변경이 발생할 때마다) 변경 사항 외에 모든 동일한 데이터로 새 객체를 만들어야 함을 의미합니다. 학교 방이있는 학교를 생각해보십시오. 학생 ... 학생의 생년월일이 지나고 나이가 바뀔 때마다 새 학교를 만들고 싶습니까? 아니면 학생 수준, 방 수준의 학생, 학교 수준의 방에서 나이를 변경할 수 있습니까?
David Rodríguez-dribeas

8
@tenpn : 불변성은 제대로 수행되면 실제로 엄청나게 잘 확장됩니다. 정말 도움이되는 한 가지는 Builder큰 불변 유형에 대한 클래스 사용입니다 (Java 및 .NET StringBuilder은 하나의 예에 불과한 클래스를 정의합니다 ).
Konrad Rudolph

24

많은 System.Collections.Generics 컨테이너에는 변경할 수없는 컬렉션을 다시 제공하는 AsReadOnly 메서드가 있습니다.


4
ReadOnlyCollection <T>가 아닌 경우에도 Ts가 변경 가능하다는 문제가 여전히 있습니다.
arynaq

4

C #에는 이러한 기능이 없습니다. 값 또는 참조로 인수를 전달할 수 있습니다. 당신은 지정하지 않는 한 그 자체가 불변 참조 심판 수정합니다. 그러나 참조 된 데이터는 변경할 수 없습니다. 따라서 부작용을 피하려면주의해야합니다.

MSDN :

매개 변수 전달


글쎄요, 그게 질문이되는 것 같아요 : const 구조가없는 부작용을 피하는 가장 좋은 방법은 무엇일까요?
tenpn

불행히도 불변 유형만이 도움이 될 수 있습니다. Spec #을 살펴볼 수 있습니다-흥미로운 컴파일 시간 검사가 있습니다.
aku

3

인터페이스가 답이며 실제로 C ++의 "const"보다 더 강력합니다. const는 "const"가 "멤버를 설정하지 않거나 멤버를 설정하는 무언가를 호출하지 않음"으로 정의되는 문제에 대한 단일 크기 솔루션입니다. 이는 많은 시나리오에서 const-ness의 좋은 속기이지만 전부는 아닙니다. 예를 들어 일부 멤버를 기반으로 값을 계산하지만 결과를 캐시하는 함수를 고려하십시오. C ++에서는 상수가 아닌 것으로 간주되지만 사용자 관점에서는 본질적으로 const입니다.

인터페이스는 클래스에서 제공하려는 기능의 특정 하위 집합을 정의하는 데 더 많은 유연성을 제공합니다. 불변성을 원하십니까? 돌연변이 메소드가없는 인터페이스를 제공하십시오. 일부 설정은 허용하고 다른 설정은 허용하지 않겠습니까? 해당 메소드만으로 인터페이스를 제공하십시오.


15
100 % 정확하지 않습니다. C ++ const 메서드는로 표시된 멤버를 변경할 수 mutable있습니다.
콘스탄틴

3
그럴 수 있지. 그리고 const-casting은 const-ness를 제거 할 수있게 해줍니다. 두 가지 모두 C ++ 설계자조차도 모든 것이 하나의 크기에 가장 적합하다는 것을 깨달았습니다.
munificent

8
C ++의 장점은 대부분의 경우 const가 있고 다른 사용자를위한 인터페이스를 구현할 수 있다는 것입니다. 이제 const 외에도 C ++에는 데이터 캐시 또는 잠금 메커니즘 (뮤텍스 등)으로 속성에 적용 할 변경 가능한 키워드가 있습니다. Const는 '내부 속성을 변경하지 않음)이 아니라 외부에서 인식되는대로 객체 상태를 변경하지 않습니다. 즉, const 메서드를 호출하기 전과 후에 객체를 사용하면 동일한 결과가 생성됩니다.
David Rodríguez-dribeas

9
C ++의 변이를 위해 const를 버리는 것은 부정한 행동 (코 악마)입니다. const_cast는 논리적으로 const가 const로 표시되지 않은 레거시 코드와 인터페이스하기위한 것입니다.
jk.

3

불변 객체를 생성하기 위해 생성자에서 초기화하는 읽기 전용 필드를 사용하는 다른 사람들의 의견에 동의하십시오.

    public class Customer
    {
    private readonly string m_name;
    private readonly int m_age;

    public Customer(string name, int age)
    {
        m_name = name;
        m_age = age;
    }

    public string Name
    {
        get { return m_name; }
    }

    public int Age
    {
        get { return m_age; }
    }
  }

또는 속성에 대한 액세스 범위를 추가 할 수도 있습니다. 즉, public get 및 protected set?

    public class Customer
    {
    private string m_name;
    private int m_age;

    protected Customer() 
    {}

    public Customer(string name, int age)
    {
        m_name = name;
        m_age = age;
    }

    public string Name
    {
        get { return m_name; }
        protected set { m_name = value; }
    }

    public int Age
    {
        get { return m_age; }
        protected set { m_age = value; }
    }
  }

3
이것들은 전체 문제에 실제로 맞지 않는 다른 접근 방식입니다. 액세스 제어 수준을 사용하면 변경 사항에서 파생 된 클래스 만 허용되며, 많은 경우 실제 세계를 적절하게 모델링하지 않습니다. 교사는 학생 기록에서 파생되지 않지만 학생이 성적을 변경할 수는 없지만 읽을 수는 있지만 학생 성적을 변경하려고 할 수 있습니다. 간단한 예를 들기 위해.
David Rodríguez-dribeas

2
  • CONST의 키워드는 같은 원시적 형 및 캐릭터 등의 컴파일 시간 상수를 사용할 수 있습니다
  • 읽기 전용 키워드는 참조 유형과 같은 런타임 상수를 사용할 수 있습니다

읽기 전용 의 문제 는 참조 (포인터)가 일정 할 수만 있다는 것입니다. 참조 된 (가리키는) 것은 여전히 ​​수정할 수 있습니다. 이것은 까다로운 부분이지만 주위에 방법이 없습니다. 상수 객체를 구현한다는 것은 변경 가능한 메서드 나 속성을 노출하지 않도록하는 것을 의미하지만 이것은 어색합니다.

참조 효과적인 C 번호 : 귀하의 C #을 개선하기 위해 50 구체적인 방법 (항목 2 - CONST에 읽기 전용 안함.)

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