C#

2011-06-14 3 views
26

에 파생 된 반환 유형이있는 추상 속성을 재정의하는 경우 클래스가 4 개 있습니다. 요청, DerivedRequest, 처리기, DerivedHandler. C#

public override DerivedRequest request { get; set; } 

사람이 일을하는 방법에 대한 아이디어가 있습니까

다음 DerivedHandler는 대신 DerivedRequest을 반환하도록이 속성을 재정의 할 필요가

public abstract Request request { get; set; } 

: 핸들러 클래스는 다음과 같은 선언과 속성이 ?

+0

이 엄격하게 좋은 OOP 없습니다. 일부 유형의 setter 연산 (비 dervied'value's)은 예기치 않게 throw됩니다. – recursive

+0

이 경우, 나는 세터가 필요 없다고 생각합니다. 개인 자산을 만들어서 생성자에서 설정할 수 있습니다. 그건 세터 운영 예외를 처리 할거야, 네? – Trevor

+0

이 경우 속성을 재정의 할 필요가 없습니다. 생성자가 DerivedRequest만을 받아들이도록하십시오. – recursive

답변

15

이 일을 구조 할 수있는 좋은 방법이 정말로되지 않습니다 :

다음은 예입니다. 다음 중 하나를 수행하십시오.

1) 리턴 유형을 변경하지 말고 서브 클래스에서 정상적으로 대체하십시오. DerivedHandler에서 기본 클래스 서명 Request을 사용하여 DerivedRequest의 인스턴스를 반환 할 수 있습니다. 원하는 경우 클라이언트 코드를 DerivedRequest으로 전송하도록 선택할 수 있습니다.

2) 다형성이 아닌 것으로 가정하면 제네릭을 사용하십시오. 이 인터페이스를 위반으로

public abstract class HandlerBase<T> where T: Request 
{ 
    public abstract T Request {get;set;} 
} 

public class Handler: HandlerBase<Request>() 

public class DerivedHandler: HandlerBase<DerivedRequest>() 
+0

파생 된 클래스를 사용하는 것과 같은 방식으로 재정의하려는 여러 속성과 같은 여러 사례가있는 경우'class HandlerBase : A : classA, B : classB, ... '와 같은 작업을 수행해야합니다. ? – Javidan

1

편집 : ... 원래 속성을 숨기고 제외

public new DerivedRequest request 
{ 
    get{return (DerivedRequest) base.request;} 
    set{base.request = value;} 
} 
public override Request request 
{ 
    get{return base.request;} 
    set{base.request = (DerivedRequest) value;} // Throws InvalidCastException if misused. 
} 
+0

이것은 일반적으로 "오버라이드"라고하지 않습니다 – Vlad

5

을 파생 형에서

: 당신은 파생 유형에 유형을 변경할 수는 없지만, new 도움이 될

public new DerivedRequest Request { get;set;} 

그러나 강력하게 권고드립니다. 재정의가 필요한 사항을 숨기면 문제가 발생합니다. 특히 부동산이 간단한 자동 생성 서비스가 아닌 경우 더욱 그렇습니다. 또한 인터페이스 또는 기본 클래스로 사용하는 경우 원래 구현 (이 경우 상속 트리에서 상위 한 클래스). 추상 클래스 또는 인터페이스를 구현하는 경우 원래 서명을 구현하지 않아도 숨길 수 없습니다.

일반적으로 new 키워드 사용을 고려하면 잘못된 경로에 있습니다. 필요하고 필요한 경우가 있지만 대부분의 경우 그렇지 않습니다.

대신에, 다른 재산합니다

public DerivedRequest DerivedRequest {/* make adequate conversions here*/ } 

그 방법을, 당신은 OOP에 관한 분명한 측면에 그리고 당신은 명확한 방법으로 정보를 얻을 수 있습니다.

+0

글쎄, 어떻게 세터를 다루겠습니까? – Vlad

+1

'DerivedRequest'는 여전히 더 이상 'Request'가 아니며 직접 할당 될 수 있습니다. – Femaref

0

이것은 이론적으로 가능하지 않습니다. 재정의는 반환 형식에 대해 공변이어야하며 (즉, 반환 형식이보다 구체적이거나 동일해야 함) 매개 변수에 반올림해야합니다. 즉 매개 변수 유형이 덜 구체적이거나 동일해야합니다. 그래서 당신의 새로운 타입은 Request과 관련하여 동시에 공변수와 반 변이가 있어야합니다. 즉, 유일한 유형은 Request입니다.

따라서 C#에서는 재정의 속성 유형을 변경할 수 없습니다.

+0

DerivedRequest가 Request보다 구체적이지 않으므로 반환 유형에 대해 대체 공변수를 사용합니까? 또는 귀하의 의견을 잘못 읽었습니까? – Trevor

+0

@threed : 속성은 getter와 setter로 구성됩니다. 문제는 세터와 함께 :-) – Vlad

6

과 같은 다른 메서드로 대체하지 않는 한 C# 언어에서 은 상속 된 메서드의 서명을 변경할 수 없습니다. 이 기술을 "멤버 숨기기"또는 "섀도 잉"이라고합니다.

.NET 2.0 이상을 사용하는 경우 Request 속성의 반환 형식을 Handler 클래스의 제네릭 형식 매개 변수로 바꾸면이 문제를 해결할 수 있습니다. 그런 다음 DerivedHandler 클래스는 해당 유형 매개 변수에 대한 인수로 DerivedRequest 클래스를 지정합니다.

// Handler.cs 
public class Handler<TRequest> where TRequest : Request 
{ 
    public TRequest Request { get; set; } 
} 

// DerivedHandler.cs 
public class DerivedHandler : Handler<DerivedRequest> 
{ 
} 
+2

당신은 확실히 그렇게 할 수 있습니다; "OOP"의 어떤 것도 Liskov 대체 원리가 유지되는 한 그렇게하지 못하게합니다. 예를 들어, 객체 지향 언어 "C++"에서는 Tiger를 반환하는 Animal을 반환하는 메서드를 재정의하는 것이 적합합니다. 이 기능은 "return type covariance"라고하며 OOP 언어에서는 상당히 일반적입니다. 그것은 C#의 기능이 아닙니다. –

+0

@ Eric Lippert 당신은 절대적으로 맞습니다. 저는 _return 타입 공분산 _ 및 _parameter 타입 contravariance_에 익숙합니다. C#은 1.0 이후 델리게이트 형식을 지원합니다. 나중에 C# 4.0에는 제네릭 인터페이스 및 대리자 형식에 대한 지원이 추가되었습니다. 실수를 지적 해 주셔서 고맙습니다. –

0
public class Request{} 

public class DerivedRequest : Request{} 

public class Handler<T> 
    where T : Request 
{ 
    public abstract T Request { get; set; } 
} 

public class DerivedHandler : Handler<DerivedRequest> 
{ 
    public override DerivedRequest Request { get; set; } 
}