C # 에서이 명백한 자체 참조의 목적은 무엇입니까?


21

내 프로젝트 중 하나에서 사용하기 위해 Piranha ( http://piranhacms.org/ ) 라는 오픈 소스 CMS를 평가하고 있습니다. 나는 적어도 나에게 다음 코드가 흥미롭고 약간 혼란 스럽다는 것을 알았다. 클래스가 같은 유형의 기본에서 상속받는 이유를 이해하는 데 도움이 될 수 있습니까?

public abstract class BasePage<T> : Page<T> where T : BasePage<T>
{
    /// <summary>
    /// Gets/sets the page heading.
    /// </summary>
    [Region(SortOrder = 0)]
    public Regions.PageHeading Heading { get; set; }
}

의 클래스 BasePage<T>가 정의되면 왜에서 상속 Page<T> where T: BasePage<T>합니까? 어떤 특정한 목적을 수행합니까?



7
공감대와 긴밀한 투표에도 불구하고 커뮤니티는 이것에 대해 잘못 생각합니다. 이것은 구체적이고 사소한 디자인 결정과 관련하여 명확하게 언급 된 질문이며,이 사이트의 핵심입니다.
Robert Harvey

닫히면 걸어서 다시 열면됩니다.
David Arno

: F-경계 다형성의 개념에 최대 읽기
Eyvind

1
@ 아이 빈드 내가 실제로했다. F-Bounded polymorphism에 관해 읽고 싶은 사람들을 위해, 여기 링크 staff.ustc.edu.cn/~xyfeng/teaching/FOPL/lectureNotes/…
Xami Yen

답변:


13

클래스가 같은 유형의 기본에서 상속받는 이유를 이해하는 데 도움이 될 수 있습니까?

에서 상속받지는 Page<T>않지만 T자체는에서 파생 된 유형에 의해 매개 변수화되도록 제한됩니다 BasePage<T>.

이유를 유추하려면 type 매개 변수 T가 실제로 어떻게 사용되는지 살펴 봐야합니다 . 파기 후에 상속 체인을 위로 올라가면이 클래스를 보게됩니다.

( github )

public class GenericPage<T> : PageBase where T : GenericPage<T>
{
    public bool IsStartPage {
        get { return !ParentId.HasValue && SortOrder == 0; }
    }

    public GenericPage() : base() { }

    public static T Create(IApi api, string typeId = null)
    {
        return api.Pages.Create<T>(typeId);
    }
}

내가 볼 수있는 한, 일반적인 제약 조건의 유일한 목적은 Create메소드가 가능한 가장 추상적 인 유형을 반환 하는지 확인하는 것 입니다.

그만한 가치가 있는지 확실하지 않지만, 그 뒤에 어떤 이유가 있거나, 단지 편의상이거나 그 뒤에 너무 많은 물질이 없을 수 있으며 캐스트를 피하는 지나치게 정교한 방법 일뿐입니다 (BTW, I '이 경우에 해당하는 것은 아닙니다. 사람들이 가끔 그렇게한다는 것입니다.)

이 그들에게 반사를 방지하기 위해 허용하지 않습니다 주 -이 api.Pages취득하고 그 페이지의 저장소입니다 typeof(T).Name, 그리고로 전달 typeId받는 contentService.Create(방법 은 여기를 참조 ).


5

이것의 한 가지 일반적인 사용은 현재 유형으로 해석되는 유형 매개 변수 인 자체 유형의 개념과 관련이 있습니다. clone()메소드 를 사용하여 인터페이스를 정의하려고한다고 가정하십시오 . 이 clone()메소드는 항상 호출 된 클래스의 인스턴스를 리턴해야합니다. 그 방법을 어떻게 선언합니까? 자체 유형이있는 제네릭 시스템에서는 쉽습니다. 그냥 반환한다고 말합니다 self. 따라서 클래스가 있으면 Fooclone 메소드를 반환하도록 선언해야합니다 Foo. Java 및 (커피 검색에서) C #에서는 옵션이 아닙니다. 대신이 클래스에서 보는 것과 같은 선언이 표시됩니다. 이것이 자기 유형과 같지 않으며 제공하는 제한이 더 약하다는 것을 이해하는 것이 중요합니다. 둘 다에서 파생 된 클래스 FooBar클래스 가 있다면BasePage, (실수하지 않은 경우) Foo를 매개 변수로 정의 할 수 있습니다 Bar. 그것은 유용 할 수 있지만 일반적으로 대부분의 경우 자기 유형처럼 사용되며 다른 유형으로 대체 할 수는 있지만 수행 해야하는 것이 아니라는 것을 이해합니다. 나는 오래 전에이 아이디어를 가지고 놀았지만 Java 제네릭의 한계 때문에 노력할 가치가 없다는 결론에 도달했습니다. C # 제네릭은 물론 더 완벽하게 기능하지만이 같은 제한이있는 것 같습니다.

이 접근법이 사용되는 또 다른 시간은 나무 또는 다른 재귀 구조와 같은 그래프와 같은 유형을 작성할 때입니다. 선언은 형식이 Page의 요구 사항을 충족하지만 형식을 더 세분화 할 수 있도록합니다. 트리 구조에서 이것을 볼 수 있습니다. 예를 들어 구현이 구현하기 위해 모든 유형의 노드를 포함하는 트리가 아니라 특정 하위 유형의 노드 (일반적으로 자체 유형)임을 정의하기 위해 a를 Node매개 변수화 Node할 수 있습니다.


3

실제로 코드를 작성한 사람이기 때문에 Filip이 정확하고 자체 참조 제네릭이 실제로 기본 클래스에 유형이 지정된 Create 메소드를 제공하는 것이 편리함을 확인할 수 있습니다.

그가 언급했듯이 여전히 많은 반사가 일어나고 있으며 결국 페이지 유형을 해결하는 데 유형 이름 만 사용됩니다. 그 이유는 동적 모델도로드 할 수 있기 때문입니다. 즉, 처음 생성 한 CLR 유형에 액세스하지 않고도 모델을 구체화 할 수 있기 때문입니다.

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