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 ...?

Foi útil?

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 "" é pouco estranho:. /

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é .De (kennel.Dogs)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top