2009-11-12 2 views
9

주어진 다음의 클래스 :방법을 상속하지만 다른 반환 유형을 사용하는 방법은 무엇입니까?

ClassA 
{ 
    public ClassA DoSomethingAndReturnNewObject() 
    {}  
} 

ClassB : ClassA 
{} 

ClassC : ClassA 
{} 

ClassBClassC이 방법을 상속하지만, 자신의 클래스에 반환 형식을 사용자 정의 얻을 수있는 방법이 있나요?

ClassA에서 메서드를 복사하고 거기에서 형식을 변경하지 않는 것이 좋습니다.

ClassB.DoSomethingAndReturnNewObject()으로 전화 할 때 ClassB 개체가 필요합니다.

ClassC.DoSomethingAndReturnNewObject()으로 전화 할 때 ClassC 개체가 필요합니다.

다음과 같이 현재 유형을 기반으로 생성자를 호출하는 것과 같습니다. this.GetType()? 하지만 실제로 어떻게 할 수 있는지 전혀 모른다.

답변

6

당신은 보호 된 가상 메서드를 만들어야합니다.

+0

좋은 생각, 나는 이것을 좋아한다. – Peterdk

8

아니요, 언급 한 기능을 return type covariance이라고합니다. C#에서는 지원되지 않습니다.

+0

비록 그것이 C# 4.0이 아니겠습니까? –

+0

jk : 아니요. C#이이 기능을 지원할 것이라고 생각하지 않습니다. C# 4.0은 제네릭에 대해 * 안전한 공동/대조 변수를 지원합니다 *. –

+0

해당 용어를 검색하면 Microsoft Connect에서도이 제안을 얻을 수 있습니다. http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=90909 –

6

설명하는 내용은 covariant return type이며 C#에서는 지원되지 않습니다.

그러나 ClassA를 공개 제네릭으로 만들고 닫힌 일반 상속인이 자신의 유형을 반환하도록 할 수 있습니다.

예 :

public abstract class ClassA<T> where T: ClassA<T>, new() 
{ 
    public abstract T DoSomethingAndReturnNewObject(); 
} 

public class ClassB: ClassA<ClassB> 
{ 
    public override ClassB DoSomethingAndReturnNewObject() 
    { 
     //do whatever 
    } 
} 
+0

"ClassB와 ClassC는 ClassA에서 상속받을 수 없으며 여전히 다형성을 지원하면서 반환 유형을 다시 정의 할 수 없습니다."- 그 의미가 확실하지 않습니다. 일반 문장 인 경우 거짓입니다. 그가 원하는 것은 공변 반환 유형입니다. 이것은 C++과 Java에서 모두 지원됩니다. 그리고 분명히 "다형성을 깨뜨리지"않습니다 - 그것이 함축되어 있다면 완벽하게 타입 안전합니다. 이는 CLR의 한계 일뿐입니다. –

+0

Generic 제약 조건에 실제로'new'가 필요할 것이고 클래스는 기본 생성자를 지원해야합니다. DoSomethingAndReturn__NewObject __() – AnthonyWJones

+0

@Anthony 오 잘 잡히는 이름에서 이것을 추측하고 있습니다. 메소드의 이름을 신경 쓰지 않았습니다. 나는 OP가 현재 인스턴스를 수정하고 이것을 반환 할 것이라고 생각하고있었습니다. – Joseph

-1

나는 새 반환 형식으로 새 기능을 작성하고 다른 함수 내에서 호출하고 반환 유형을 조작 할 필요가 있다고 생각합니다. 그렇지 않으면 논리적이지 않습니다! (상속의 정의/아이디어 포함)

+0

downvote- please explain ... – Dani

0

아마도 제네릭이 구세주가 될 것입니다. 이 링크에서보세요 : C# Generics Part 3/4: Casting, Inheritance, and Generic Methods

bstract class B<T> { 
    public abstract T Fct(T t); 
} 
class D1 : B<string>{ 
    public override string Fct(string t) { return "hello"; } 
} 
class D2<T> : B<T>{ 
    public override T Fct(T t) { return default (T); } 
} 
0

음, 정답은 결코하고, 일반적으로,이 나쁜 생각하지 않습니다. 뭔가 완전히 다른 것을 반환하는 경우 다른 방법을 찾으십시오.

그러나 완전히 다른 것을 반환하지 않으면 인터페이스가 문제를 해결할 수 있습니다. 클래스를 반환하는 대신 인터페이스를 반환하고 클래스 A, B 및 C가 해당 인터페이스를 구현하는 객체를 적절한 방식으로 반환하도록합니다.

+2

반환 유형이 "완전히 다른 것"이 아닙니다. ClassB와 ClassA 사이에는 "is-a"관계가 있습니다. 원래 반환 값의보다 구체적인 반환 유형을 선언해도 Liskov 대체 원칙을 위반하지 않습니다. 사실 java는 java 1.5부터 허용합니다. 입력 인수에 대해서는 반대가 사실입니다.보다 일반적인 입력 인수를 선언하면 파생 클래스에서 허용되어야합니다. –

+1

네, 궁극적 인 질문은 왜 그것이 B 클래스인지 C 클래스인지 신경 써야한다는 것입니다. 당신이 뭔가 특별한 것을 원한다면 그의 요지는 정확합니다. – Min

+0

wcoenen, 문제를 이해하고 있는지 잘 모르겠습니다. 현재 대중적인 대답은 좋은 해결책입니다. 하위 클래스가 실제로 더 구체적인 반환 값을 가져야한다고 말하면 (지원되지 않기 때문에 우리가이 문제를 논의하는 이유를 모르겠습니다), 그러면 동의하지 않습니다. 나쁜 모양이에요. –

0

메서드의 반환 형식이 서명의 일부이기 때문에 상속되지 않습니다. 당신은 방법을 바꾸지 않고 완전히 새로운 것을 만들 것입니다.

몇 가지 옵션이 있습니다. 예를 들어, DoSomethingAndReturnNewObject 메서드를 제네릭 기반 메서드로 만들고 해당 제네릭 형식을 반환 할 수 있습니다. 이것은 아마도 당신이 찾고있는 정확한 행동에 대한 가장 직접적인 경로 일 것입니다.

다른 방법은 메서드 서명을있는 그대로두고 하위 클래스 메서드가 ClassBClassC의 인스턴스를 반환하도록하는 것입니다. 그런 다음 클라이언트 코드는 해당 객체를 적절한 파생 클래스로 사용하기 위해 형 변환을 담당해야합니다.

ClassA의 공용 인터페이스로 충분하지 않은 이유가 있습니까?다형성은 가상 멤버를 올바르게 파생하고 재정의 한 경우 ClassA 멤버 만 사용하는 경우 올바른 기능을 제공합니다.

class ClassA 
{ 
    protected virtual ClassA Create() 
    { 
     return new ClassA() 
    } 

    public ClassA DoSomethingAndReturnNewObject() 
    { 
     ClassA result = Create(); 
     // Do stuff to result 
     return result; 
    } 
} 

class ClassB : ClassA 
{ 
    protected override ClassA Create() { return new ClassB(); } 
} 

class ClassC : ClassA 
{ 
    protected override ClassA Create() { return new ClassC(); } 
} 

참고 반환 형식이를 ClassA 남아 있지만, 객체 인스턴스 유형은 특정 클래스가 될 것이다 다음 DoSomethingAndReturnNewObject 사용하는

2
class ClassA<T> where T : ClassA<T>, new() 
{ 
    public T DoSomethingAndReturnNewObject() 
    { 
     return new T(); 
    } 
} 

class ClassB : ClassA<ClassB> { } 

class ClassC : ClassA<ClassC> { } 

테스트 :

ClassB b1 = new ClassB(); 

ClassB b2 = b1.DoSomethingAndReturnNewObject(); // returns instance of ClassB 
0

나는 마지막으로 다음과 같은 솔루션을 고안했다. 필자의 경우에는 충분히 유용하지만 ClassA는 파생 상품이라는 것을 알고 있으며이 두 가지 옵션으로 제한되어 있다고 가정합니다. 실제로는 고차원 적 사고는 아니지만 작동합니다. :)

ClassA 
{ 
    public ClassA DoSomethingAndReturnNewObject() 
    { 
     if (this.GetType() == typeOf(ClassB)) 
     { 
      return new ClassB(values); 
     } 
     else 
     { 
      return new ClassC(values): 
     } 
    }  
} 

ClassB : ClassA 
{} 

ClassC : ClassA 
{} 
-2

정말 간단하게 대답이 있습니다. 모든 메소드가 "객체"유형을 반환하도록하십시오. 당신은 분명히 다른 유형, 문자열과 ints와 what잎을 반환하고, 그들이 목적지에 도달 한 후에도 그대로 남아있을 것입니다. 그러나 컴파일러는 완벽하게 행복합니다. 모든 것이 "객체"입니다. 당신은 좋은 일이 아닌 컴파일 타임 타입 검사를 포기하지만, 몇 가지 깊은 OO 프로그래밍을 위해 때때로 반환이 가치가 있습니다.

관련 문제