그것은 잘못을 캐스팅하려면 열거자 아이의 등을 열거자의 부모 등?
-
04-07-2019 - |
문제
나에 오류가 나를 구축합니다:
오류 12 할 수 없는 암시적으로 변환 유형 '시스템이다.컬렉션이 있습니다.일반적입니다.IEnumerator<공공 무>' 하기 '시스템이다.컬렉션이 있습니다.일반적입니다.IEnumerator< IParentClass>'.는 명시적 변환 존재하는(당신은 당신 누락 캐스팅?)
그것은 잘못을 단순히 발리?
이것은 나의 코드:
public Dictionary<Int32, BaseClass> Map { get; private set; }
public IEnumerator<BaseClass> GetEnumerator()
{
return this.Map.Values.GetEnumerator();
}
public IEnumerator<IParentClass> IEnumerable<IParentClass>.GetEnumerator()
{
return this.GetEnumerator(); // ERROR!
}
나의 질문은,나는 그냥 변경이 라인:
return this.GetEnumerator();
하기:
return (IEnumerator<IParentClass>)this.GetEnumerator();
(지 않고 어떤 나쁜 부작용)?
접수 응답:
내가 변했어요 기능은 다음(을 읽은 후에 존 스키트의 게시물):
IEnumerator<IParentClass> IEnumerable<IParentClass>.GetEnumerator()
{
return this.Map.Values.Cast<IParentClass>().GetEnumerator();
}
해결책
현재 C#에서 제네릭이 공분산이 아니기 때문에 할 수 없습니다. .NET 자체에는 약간의 지원이 있지만 (대표 및 인터페이스의 경우) 아직 사용되지 않았습니다.
당신이 돌아왔다면 IEnumerable<BaseClass>
대신에 IEnumerator<BaseClass>
(및 .NET 3.5를 가정) 사용할 수 있습니다 Enumerable.Cast
-하지만 현재 자신의 확장 방법을 작성해야합니다.
public static IEnumerator<TParent> Upcast<TParent, TChild>
(this IEnumerator<TChild> source)
where TChild : TParent
{
while (source.MoveNext())
{
yield return source.Current;
}
}
또는 귀하의 경우에 귀하는 이전에 캐스트를 사용할 수 있습니다.
return this.Map.Values.Cast<BaseClass>().GetEnumerator();
다른 팁
아니요, 최소한 C# 3.0 이하의 인터페이스 분산은 지원되지 않습니다. Eric Lippert의 우수한 시리즈, 특히, 특히 이 하나.
아니요, 안전하지 않습니다. 아래를 참조하십시오.
System.collections.generic 사용; 클래스 foo {} 클래스 바 : foo {}
static class Program
{
static IEnumerator<Foo> GetBase() {
yield return new Foo();
yield return new Bar();
}
static IEnumerator<Bar> GetDerived()
{
return (IEnumerator<Bar>)GetBase();
}
static void Main()
{
var obj = GetDerived(); // EXCEPTION
}
}
그러나 반복자 블록을 사용하여 캐스트를 수행 할 수 있어야합니까?
static IEnumerator<Bar> GetDerived()
{
using (IEnumerator<Foo> e = GetBase())
{
while (e.MoveNext())
{
// or use "as" and only return valid data
yield return (Bar)e.Current;
}
}
}
하는 이유 유 이에 적합하지 않은,그림이 대신 Enumerator
, 이, List
.모두 사용하여 제네릭-컴파일러가 처리하지 않거나 특별한 방법에 관한 일반적인 인수입니다.
void doStuff() {
List<IParentThing> list = getList();
list.add(new ChildThing2());
}
List<IParentThing> getList() {
return new List<ChildThing1>(); //ERROR!
}
이 첫번째 방법은 고급 목록 IParentThing
s 해야 할 수 있을받을 ChildThing2
.하지만 목록 ChildThing1
s 을 처리할 수 없습니다 ChildThing2
, 또는 실제로 어떤 구현자의 IParentThing
보 ChildThing1
-즉,는 경우 List<ChildThing1>
되었으로 캐스팅 List<IParent>
, 그할 수 있어야를 다루 모든 스 IParentThing
, 지 IParentThing
고 ChildThing1
.
참고하는 자바 generics 있는 방법을 말하는"나는 아무것도의 목록에서 상속되는"이 외에도"내가 목록을 원하는 것 이 상속,"할 수있는 더 많은 흥미로(그리고 내 생각에는 우아한)솔루션은 좀 문제가 발생합니다.
IEnumerator<BaseClass>
그리고 IEnumerator<ParentClass>
관련이없는 일반적인 매개 변수는 관련이 없습니다. 대신 LINQ를 사용하겠습니다 Select
그렇게와 같은 확장 방법 :
return this.Select(x => (IParentClass)x).GetEnumerator();
아니면 그 Cast
확장 방법 :
return this.Cast<IParentClass>().GetEnumerator();