2008-11-13 3 views
2

필자가 쓰는 일반 메서드에 문제가 있습니다. 다음 서명이 있습니다.C# 일반 메서드에서 캐스팅 문제가 발생했습니다.

public static ThingCollection<T> GetThings<T>(...) where T : Thing 

몇 가지 클래스가 있습니다. ThingA, ThingB 및 ThingC는 Thing을 상속받습니다. 이 메소드에서 이와 비슷한 코드를 사용할 수 있기를 원합니다.

var things = new ThingCollection<T>(); 

if (typeof(T) == typeof(Thing)) 
    foreach (var item in someCollection) 
    things.Add((T)new Thing(...)); 
else if (typeof(T) == typeof(ThingA)) 
    foreach (var item in someCollection) 
    things.Add((T)new ThingA(...)); 
else if (typeof(T) == typeof(ThingB)) 
    foreach (var item in someCollection) 
    things.Add((T)new ThingB(...)); 
else if (typeof(T) == typeof(ThingC)) 
    foreach (var item in someCollection) 
    things.Add((T)new ThingC(...)); 
else 
    throw new Exception("Cannot return things of type " + typeof(T).ToString()); 

return things; 

문제

내가 새로운 개체를 캐스팅하지 않는 경우 최고의 오버로드 된 메서드 경기가 무효 인수를 오류가 얻을 수 있다는 것입니다. 위에 표시된대로 T 캐스트를 추가하는 것이 새로운 Thing()에 적합하지만 보고서 다른 새로운 호출의 경우 'ThingA'유형을 'T'으로 변환 할 수 없습니다. Intellisense는 T가 Thing이라는 것을 나타냅니다.하지만 다른 객체를 Thing으로 상속 할 수없는 이유를 이해하지 못합니다.

아마도 이것은 내가하려는 일을하는 올바른 방법이 아닙니다. 나는 올바른 길을 가고 있는가? 아마 약간의 작은 뉘앙스를 놓치거나 내가 완전히 다른 것을해야합니까?

답변

7

나는 그 코드로 무엇을 하려는지 모르겠다.

Thing에서 파생 된 모든 유형의 클래스를 추가 할 수있는 곳의 컬렉션을 만들려면 ThingCollection에 유형 이름이 없어야합니다. 구체적인 유형의 컬렉션으로 간주됩니다.

예컨대하는 ThingCollection 이런 식으로 구현 :

public class ThingCollection : List<Thing> {} 

지금 당신이 ThingA, ThingB 및 ThingC는 것은 상속 물론 가정

ThingCollection tc = new ThingCollection(); 
tc.Add(new ThingA()); 
tc.Add(new ThingB()); 
tc.Add(new ThingC()); 

할 수 있습니다.

GetThings()을 사용하여 파생 된 유형의 항목을 필터링하려는 경우, 즉 GetThings()에 대한 호출이 ThingCollection을 반환하기를 원합니다.

+0

큰 도움이되었습니다. 일반 목록에서 상속 받기 때문에 ThingCollection을 일반화 할 필요가 없다는 사실을 깨닫지 못했기 때문에 제네릭에 대한 이해를 얻으려고 싸우고있었습니다. –

2

공용 인터페이스 (IThing)를 사용하는 경우이를 캐스팅 할 수 있어야합니다.

3

기본적으로이 코드 단편의 디자인은 좋지 않습니다. "ThingD"클래스를 추가하면 명확한 동작을 위해 코드의 다른 부분을 변경해야합니다. 당신은 같은 것을 사용해야합니다

public static ThingCollection<T> GetThings<T>(...) where T : Thing, new() 
... 
... 
T item = new T(); 
item.Something = Whatever(); 

또는 당신이 "ICloneable"인터페이스 INT의 것 클래스를 구현할 수 있습니다.

3

코드는 T를 사용하기 전에 T의 유형을 테스트하려고하므로 Liskov 대체 원칙을 위반합니다.

사전/전략 조합 또는 방문자 패턴을 사용하지 않으려면이 문제를 방지하십시오.

T가 ThingB 인 경우 캐스트 (T) ThingA가 유효하지 않으므로 코드가 실제로 잘못되었습니다.

관련 문제