C # não pode converter de IEnumerable para IEnumerable
-
10-07-2019 - |
Pergunta
Eu recentemente ter problemas ao tentar AddRange (IEnumerable) para uma lista. Provavelmente uma questão clássica, mas eu realmente não obtê-lo ainda.
Eu entendo que os métodos que esperam uma lista de parâmetros não estiver satisfeito com uma lista, porque eles podem tentar adicionar uma base para a lista, que é obviamente impossível.
Mas se eu conseguir isso corretamente, desde IEnumerables si não pode ser alterado, ele deve trabalhar neste caso.
O código i pensado parecido com este:
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
}
}
Tentei passar uma dica para o compilador no método AddRange2, mas esta acabou de se mudar para o problema de volta.
É a minha maneira de pensar falho? Será esta uma limitação da língua ou é por design?
IIRC, o suporte para este tipo de operações foi adicionado ao Java 1.5, talvez por isso, será adicionado ao C #, em algum momento no futuro, também ...?
Solução
Esta é covariância, e será corrigido em C # 4.0 / .NET 4.0. Por enquanto, a opção genérica é a melhor resposta (para IEnumerable<T>
- não IList<T>
etc ).
Mas dentro do método genérico, você tem que pensar em termos de T
. Você também pode usar Cast<T>
ou OfType<T>
com LINQ para conseguir algo similar.
Outras dicas
Em C # 3.0 você pode usar o "Elenco" método de extensão. Se você importar System.Linq e então usar este código:
public void AddRange2<T>(IEnumerable<T> foos) where T : Foo
{
m_Foos.AddRange (foos.Cast<Foo>());
}
Em seguida, ele deve trabalhar para você.
Não é resolver com método de extensão:
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>() );
mas o "
A solução elenco de curso pode gerado exceções elenco de classe. A pessoa que publicou o trabalho de extensão enumeráveis ??torno disse que era estranho. Eu vim com uma solução que é apenas metade tão estranho, não sei se vou usá-lo:
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);
}
}
Uso:
= IEnumerable mamíferos até