2014-04-06 2 views
2

ObservableCollection<T>은 6 ObservableCollection List<Parent>이며, 모두 다른 유형의 하위 클래스가 있습니다.부모 클래스를 자식으로 변환합니다.

우리가하고자하는 것은 제네릭 메소드를 사용하여 동일한 유형의 모든 객체를 검색하는 것입니다. 즉, 모든 <T> 자식을 포함하는 목록을 검색하십시오.

여기 내 소스 코드

클래스 A는 B는 부모의 자식 클래스입니다.

(ManagerListStack.Where(x => x._Type == typeof(T)).First().List as List<T>) 

반환 된 목록을 사용하여

ObservableCollection<ManagerTemplate> ManagerListStack = new ObservableCollection<ManagerTemplate>(ManagerTemplates); 


class ManagerTemplate 
{ 
public Type _Type { get; set; } 
public ObservableCollection<Parents> parentList {get;set;} 
} 

internal static List<ManagerTemplate> ManagerTemplates = new List<ManagerTemplate>() 
{ 
    new ManagerTemplate{ List= new ObservableCollection<Parent>(),Type=typeof(A)}, 
    new ManagerTemplate{ List= new ObservableCollection<Parent>(),Type=typeof(B)} 
}; 

public static List<T> Get<T>() where T : Parent 
{ 
    /*(ManagerListStack.Where(x => x._Type == typeof(T)).First().List.Cast<T>()).ToList(); -- TRY 1*/ 
    /*(List<T>)(ManagerListStack.Where(x => x._Type == typeof(T)).First().List.Cast<T>())* -- TRY 2*/ 
    return (ManagerListStack.Where(x => x._Type == typeof(T)).First().List.Cast<T>()).ToList(); 
} 

더 elements.I 100 % 확신하지 않고 목록을 디버깅 한 포함하고, 요소 내부에있다.

(List<T>)(ManagerListStack.Where(x => x._Type == typeof(T)).First().List.Cast<T>()) 

사용

내가 'A 또는 B 부모로부터 캐스팅 할 수 없습니다'오류가 발생

+0

내가 ManagerTemplate 항상 하나의 Obeservable를 개최 것을 올바르게 이해한다 "내가하는 A 해요"인쇄 부모의 단일 유형의 수집? – Martijn

+0

네, 맞습니다. 각 ManagerTemplate 내부에는 동일한 유형의 객체를 포함하는 단일 ObserableCollection이 있습니다. – user2920222

+1

그리고 당신의 질문은 무엇입니까? 당신은 이미 해결책이있는 것 같습니다. –

답변

1

SomeListOfX as List<Y>이 작동하지 않습니다. YX에서 파생된다는 사실은 List<Y>List<X>에서 파생된다는 것을 의미하지 않습니다! 이 두 목록 유형은 호환되지 않습니다. 그들은 단순히 두 가지 유형입니다. 의 항목 만 포함되어 있어도유형의 항목 만 포함되어 있어도 C#은 런타임 형식이 아닌 컴파일 할 때 정적 형식 만 알고 있기 때문에 으로 캐스팅 할 수 없습니다. 목록에 유형이 Child이 아닌 항목이 포함될 수 있습니다.

그런데 그 반대는 작동하지 않습니다. List<Child>List<Parent>으로 전송할 수 있다면 Parent 또는 AnotherChild 유형의 항목을 List<Parent>에 추가 할 수 있지만 기본 목록은 여전히 ​​List<Child> 유형이므로 f ***까지 올릴 수 있습니다. 객체를 형 변환한다고해서 새 객체가 생성되지는 않습니다. 즉, 객체를 변형하지 않습니다. C#에서 다른 유형으로 간주하도록 지시합니다. 예 : parent이 아동을 언급한다는 것을 알고 있다면 Child child = (Child)parent;라고 말할 수 있습니다.

(List<T>)(ManagerListStack.Where(x => x._Type == typeof(T)).First().List.Cast<T>()) 

Cast<T>에서


IEnumerable<T> 산출 당신은 List<T>IEnumerable<T> 캐스팅 수 없습니다! 열거 형은 목록이 아닙니다. XY에 캐스트 할 수있는 경우에 작동 무엇


List<Y> listOfY = listOfX.Cast<Y>().ToList(); 

입니다.Get<T> 작품


세 번째 (주석) 예 : 올리비에 위에서 말했듯의

return ManagerListStack 
    .Where(x => x._Type == typeof(T)) 
    .First().List 
    .Cast<T>() 
    .ToList(); 
1

먼저,하는 List<Child>ChildParent의 아이 인 경우에도 List<Parent>의 서브 클래스가 아닙니다. ObservableCollection에서도 마찬가지입니다. 이 주제를 분산이라고합니다. 여기에 대해 깊이 논의하기에는 너무 멀어 지지만 자세한 내용은 C# : Is Variance (Covariance/Contravariance) another word for Polymorphism?을 참조하십시오. IEnumerable<T>은 공변이다. 나는 그것으로 전환 할 것이다. 목록 또는 관찰 가능한 컬렉션이 특별히 필요하면 나중에 다르게 구성하거나 피드를 제공 할 수 있습니다.

ObservableCollection에서 임의의 IEnumerable을 반환하는 강력한 형식의 Get 함수가 있어야합니다. 여기서 U 우리가 서명을 쓸 수있는 경우 T.의 아이가 볼 수 있습니다 :

우리가 원하는 것을 가장 추상적 버전을하지만 우리가 실제로 일반적인 것을 할 필요가 없습니다 IEnumerable<U> Get<U, T>(ObservableCollection<IEnumerable<T>> source) where U : T

: 우리가 이미 알고있는 컴파일시의베이스 형 쉽게 읽고, 우리는 더 특정 할 수 있습니다 :

IEnumerable<U> Get<U>(ObservableCollection<IEnumerable<Parent>> source) where U : Parent

는 이제 함수의 본문을 작성 할 수 있습니다 :

IEnumerable<U> Get<U>(ObservableCollection<IEnumerable<Parent>> source) where U : Parent { 
    return source.First(inner => inner is IEnumerable<U>) 
} 

와우, 즉 실제로는 매우 간단합니다!

이것은 실제로 원하는 API가 아닙니다. ObservableCollectionsObservableCollections : 우리는 모든 것을 함께 넣어 경우, 우리는 여전히 당신이 원하는 행동을하지 않아도, 지금

ObservableCollection<IEnumerable<Parent>> ManagerListStack = new ObservableCollection<IEnumerable<Parent>>(ManagerTemplates); 


internal static List<IEnumerable<Parent>> ManagerTemplates = new List<IEnumerable<Parent>> 
{ 
    new IEnumerable<ChildA>(){}, 
    new IEnumerable<ChildB>(){}, 
}; 

IEnumerable<U> Get<U>() where U : Parent { 
    return ManagerListStack.First(inner => inner is IEnumerable<U>) 
} 

를 얻을. 우리가 C#의 타입 시스템에서 제대로 할 수 없다는 것이 밝혀졌습니다. 그러나 우리가 할 수있는 일은 타입 시스템에서 프로그래머로 책임을 이동시키는 것입니다. ObservableCollection<IEnumerable<Parent>>은 그대로 유지하지만 ObservableCollections<Child>으로 채 웁니다. 이것은 ObservableCollection<Child>IEnumerable<Child>이고, IEnumerable<Child>IEnumerable<Parent>의 부속 유형이기 때문에 가능합니다.

ObservableCollection<IEnumerable<Parent>> ManagerListStack = new ObservableCollection<IEnumerable<Parent>>(ManagerTemplates); 


internal static List<IEnumerable<Parent>> ManagerTemplates = new List<IEnumerable<Parent>> 
{ 
    new ObservableCollection<ChildA>(){}, 
    new ObservableCollection<ChildB>(){}, 
}; 

ObservableCollection<U> Get<U>() where U : Parent { 
    return (ObservableCollection<U>)ManagerListStack.First(inner => inner is ObservableCollection<U>) 
} 

우리는

을 공동 변형 ObservableCollection에 제공하지 않습니다 도서관의 한계를 해결하기 위해 (어쨌든 불가능한 것 같다, 그래서 그들을 비난하지 않는다) 탈출 해치로 캐스트를 사용

내가 시험에 LinqPad에 사용 된 전체 프로그램은 :

예상대로
void Main() 
{ 
    new Test().Get<ChildA>().First().Talk(); 
} 

class Test { 

     internal List<IEnumerable<Parent>> ManagerTemplates; 
     private ObservableCollection<IEnumerable<Parent>> ManagerListStack; 

     public Test() { 
     this.ManagerTemplates = new List<IEnumerable<Parent>> 
     { 
      new ObservableCollection<ChildA>(){ new ChildA()}, 
      new ObservableCollection<ChildB>(){ new ChildB()}, 
     }; 

     this.ManagerListStack = new ObservableCollection<IEnumerable<Parent>>(this.ManagerTemplates); 
     } 

     public ObservableCollection<U> Get<U>() where U : Parent { 
      return (ObservableCollection<U>)ManagerListStack.FirstOrDefault(inner => inner is ObservableCollection<U>); 
     } 
} 

abstract class Parent { 
    abstract public void Talk(); 
} 

class ChildA : Parent { 
    public override void Talk(){ 
     Console.WriteLine("I'm an A"); 
    } 

} 

class ChildB : Parent { 
public override void Talk(){ 
     Console.WriteLine("I'm a B"); 
    } 
} 

, 그것은

관련 문제