C#은 ienumerable 에서 ienumerable 로 변환 할 수 없습니다.
-
10-07-2019 - |
문제
나는 최근에 목록에 부가 (ienumerable)를 추가하려고 할 때 문제가 발생합니다. 아마도 고전적인 문제 일 것입니다. 그러나 나는 아직 그것을 얻지 못합니다.
목록 매개 변수를 기대하는 메소드는 목록에 만족하지 않는다는 것을 이해합니다. 왜냐하면 목록에 기본을 추가하려고 시도 할 수 있기 때문입니다.
그러나 Ienumerables 자체를 변경할 수 없으므로이 경우 올바르게 얻을 수 있으므로이 경우 작동해야합니다.
내가 생각한 코드는 다음과 같이 보입니다.
class Foo
{
}
class Bar : Foo
{
}
class FooCol
{
private List<Foo> m_Foos = new List<Foo> ();
public void AddRange1(IEnumerable<Foo> foos)
{
m_Foos.AddRange (foos); // does work
}
public void AddRange2<T>(IEnumerable<T> foos) where T : Foo
{
m_Foos.AddRange (foos); // does not work
}
}
class Program
{
static void Main(string[] args)
{
FooCol fooCol = new FooCol ();
List<Foo> foos = new List<Foo> ();
List<Bar> bars = new List<Bar> ();
fooCol.AddRange1 (foos); // does work
fooCol.AddRange1 (bars); // does not work
fooCol.AddRange2 (foos); // does work
fooCol.AddRange2 (bars); // does work
}
}
AddRange2 메소드에서 컴파일러에 힌트를 전달하려고했지만 이것은 문제로 이동했습니다.
내 사고 방식은 결함이 있습니까? 이것은 언어의 한계입니까, 아니면 디자인에 의한 것입니까?
IIRC, 이러한 종류의 작업에 대한 지원은 Java 1.5에 추가되었으므로 향후 어느 시점에서도 C#에 추가 될 것입니다 ...?
해결책
이것은 공분산이며 C# 4.0 / .NET 4.0에 고정됩니다. 지금은 일반 옵션이 최고의 답변입니다 ( IEnumerable<T>
- ~ 아니다 IList<T>
등).
그러나 일반적인 방법 내에서, 당신은 T
. 당신은 또한 사용할 수 있습니다 Cast<T>
또는 OfType<T>
비슷한 것을 달성하기 위해 LINQ와 함께.
다른 팁
C# 3.0에서는 "캐스트"확장 방법을 사용할 수 있습니다. System.linq를 가져 오면이 코드를 사용하는 경우 :
public void AddRange2<T>(IEnumerable<T> foos) where T : Foo
{
m_Foos.AddRange (foos.Cast<Foo>());
}
그러면 그것은 당신을 위해 작동해야합니다.
확장 방법이있는 해결 방법이 있습니다.
public static IEnumerable<TBase> ToBaseEnumerable<TBase, TDerived>( this IEnumerable<TDerived> items ) where TDerived : TBase {
foreach( var item in items ) {
yield return item;
}
}
...
IEnumerable<Employee> employees = GetEmployees(); //Emplyoee derives from Person
DoSomethingWithPersons( employees.ToBaseEnumerable<Person, Employee>() );
하지만 "u003CPerson, Employee> "조금 어색하다 :/.
물론 캐스트 솔루션은 클래스 캐스트 예외를 생성 할 수 있습니다. 열거 가능한 확장을 게시 한 사람은 그것이 어색하다고 말했다. 나는 어색한 절반에 불과한 솔루션을 생각해 냈습니다.
public static class UpTo<T>
{
public static IEnumerable<T> From<F>(IEnumerable<F> source) where F:T
{
// this cast is guaranteed to work
return source.Select(f => (T) f);
}
}
용법:
ienumerable 포유류 = up tou003CMammal> .from (Kennel.Dogs)