C# 제네릭 및 다형성 : 옥시 모론?
-
06-07-2019 - |
문제
C#의 제네릭에 대해 이해 한 내용을 확인하고 싶습니다. 이것은 제가 일반 기본 클래스가 유형-안전 파생 인스턴스를 만드는 데 사용되는 몇 가지 코드베이스에서 나타났습니다. 내가 말하는 것에 대한 아주 간단한 예,
public class SomeClass<T>
{
public virtual void SomeMethod(){ }
}
public class DeriveFrom :SomeClass<string>
{
public override void SomeMethod()
{
base.SomeMethod();
}
}
파생 된 인스턴스를 다형성 방식으로 사용하고 싶을 때 문제가 발생합니다.
public class ClientCode
{
public void DoSomethingClienty()
{
Factory factory = new Factory();
//Doesn't compile because SomeClass needs a type parameter!
SomeClass someInstance = factory.Create();
someInstance.SomeMethod();
}
}
일단 상속 계층 또는 인터페이스에 제네릭을 소개하면 더 이상 해당 클래스 제품군을 그 자체를 제외하고 다형성 방식으로 사용할 수없는 것 같습니다. 그게 사실인가요?
해결책
내가 볼 수있는 한, 코드를 소비하면 일반 클래스의 세부 사항이 필요하지 않습니다 (즉, 무엇에 의존하지 않습니다. T
이다). 따라서 인터페이스를 소개하지 않겠습니까? SomeClass<T>
이 인터페이스의 인스턴스를 구현하고 사용합니다.
예 :
public interface ISome
{
void SomeMethod();
}
public class SomeClass<T>: ISome
{
public virtual void SomeMethod(){ }
}
public void DoSomethingClienty()
{
Factory factory = new Factory();
ISome someInstance = factory.Create();
someInstance.SomeMethod();
}
이제 서브 클래스 SomeClass<T>
다르게 작동 할 수 있습니다 T
S이지만 코드 소비는 변경되지 않습니다.
다른 팁
나는 당신이 제네릭의 요점을 오해하고 있다고 생각합니다. 제네릭을 사용하면 유형이 필요한 클래스를 일반화 할 수 있지만 특히 어떤 유형이든 상관하지 않습니다. 예를 들어, a List<string>
문자열 목록이지만 무엇을 List
이다? 아무것도없는 목록을 갖는 것은 다소 쓸모없는 개념입니다.
각 전문 수업 (즉, List<string>
) 이다 고유 한 유형입니다, 그리고 컴파일러는이를 그렇게 취급합니다. 그것은이다 가능한 일반 유형 자체에 도달하려면 (typeof(List<>)
예를 들어), 그러나 대부분의 경우에는 쓸모가 없으며, 확실히 인스턴스를 만들 수는 없습니다.
나는 모든 일반 유형의 기본 역할을하기 위해 추상 클래스를 사용하는 것을 선호합니다.
public abstract class SomeClass
{
public abstract void SomeMethod();
}
public class SomeClass<T> : SomeClass
{
public override void SomeMethod() { }
}
public class DeriveFrom<String> : SomeClass<String>
{
public override void SomeMethod() { base.SomeMethod(); }
}
상속 계층 또는 인터페이스에 제네릭을 소개하면 더 이상 해당 클래스 제품군을 다형성 방식으로 사용할 수없는 것 같습니다.
맞습니다.이 상황과 매우 유사합니다.
class StringContainer
{
}
class IntContainer
{
}
StringContainer container = new IntContainer(); // fails to compile
그러나 당신은 이것을 할 수 있습니다 :
class Container
{
}
class Container<T> : Container
{
}
Container container = new Container<String>(); // OK
당신이 찾고있는 것은 다음과 같습니다.
SomeClass(of someType) someInstance = factory(of someType).Create(); or maybe SomeClass(of someType) someInstance = factory.Create(of someType)(); or SomeClass(of someType) someInstance = factory.Create();
다른 일반 클래스를 생성하기위한 공장 클래스 세트를 가질 수 있거나 일반 유형 매개 변수가있는 공장을 가질 수 있습니다. 일반적인 클래스 자체가 아니라 클래스. 하나의 특정 형태의 일반 유형의 인스턴스를 반환하도록 설계된 공장을 가질 수도 있습니다.
public Class ReflectionReport<T>
{
// This class uses Reflection to produce column-based grids for reporting.
// However, you need a type in order to know what the columns are.
}
... so, in another class you have...
public Class ReflectionReportProject {
ReflectionReport<Thang> thangReport = new ReflectionReport<Thang>();
ReflectionReport<Thong> thongReport = new ReflectionReport<Thong>();
... some more stuff ...
// Now, you want to pass off all of the reports to be processed at one time....
public ReflectionReport<????>[] ProvideReports()
{
return new ReflectionReport<????>[] { thangReport, thongReport } ;
}
}