Sugestões desejadas com listas ou enumeradores de T ao herdar de classes genéricas

StackOverflow https://stackoverflow.com/questions/53395

  •  09-06-2019
  •  | 
  •  

Pergunta

Sei que a resposta não será simples e já uso alguns tacos (acho feios).Estou simplesmente procurando algumas respostas elegantes.

Classe abstrata:

public interface IOtherObjects;

public abstract class MyObjects<T> where T : IOtherObjects
{
   ...

   public List<T> ToList()
   {
       ...
   }
}

Crianças:

public class MyObjectsA : MyObjects<OtherObjectA> //(where OtherObjectA implements IOtherObjects)
{


}

public class MyObjectsB : MyObjects<OtherObjectB> //(where OtherObjectB implements IOtherObjects)
{


}

É possível percorrer uma coleção de MyObjects (ou outro agrupamento semelhante, genérico ou não) para então utilizar para Listar método do Meus Objetos classe base, pois não sabemos especificamente o tipo de T neste momento.

EDITARQuanto a exemplos específicos, sempre que isso surge, penso nisso há algum tempo e, em vez disso, faço algo diferente, portanto não há nenhum requisito atual.mas como tem surgido com bastante frequência, pensei em flutuar.

EDITAR@Sara, não é o tipo específico de coleção que me interessa, poderia ser uma Lista, mas ainda assim o método ToList de cada instância é relativamente inutilizável, sem um tipo anônimo)

@aku, é verdade, e esta questão pode ser relativamente hipotética, porém ser capaz de recuperar e trabalhar com uma lista de T de objetos, sabendo apenas seu tipo base seria muito útil.Fazer com que o ToList retorne um List Of BaseType foi uma das minhas soluções alternativas

EDITAR @ todos:Até agora, este tem sido o tipo de discussão que eu esperava, embora confirme em grande parte tudo o que eu suspeitava.Obrigado a todos até agora, mas qualquer outra pessoa fique à vontade para contribuir.

EDITAR@Rob, Sim, funciona para um tipo definido, mas não quando o tipo é conhecido apenas como Lista de IOtherObjects.

@Roubar De novo Obrigado.Essa geralmente tem sido minha solução alternativa desajeitada (sem desrespeito :)).Isso ou usar a função ConvertAll para Downcast por meio de um delegado.Obrigado por dedicar seu tempo para entender o problema.

EDIÇÃO QUALIFICADA caso eu esteja um pouco confuso

Para ser mais preciso, (posso ter deixado minha implementação mais recente ficar muito complexa):

digamos que tenho 2 tipos de objetos, B e C, herdados do objeto A.

Muitos cenários se apresentaram onde, a partir de uma Lista de B ou de uma Lista de C, ou em outros casos, de uma Lista de qualquer um deles - mas não sei se estou em uma classe base, precisei de uma Lista de A.

O exemplo acima foi um exemplo diluído do Lista de menos específicos última encarnação do problema.

Geralmente ele se apresenta, conforme penso, em possíveis cenários que limitam a quantidade de código que precisa ser escrito e parece um pouco mais elegante do que outras opções.Eu realmente queria uma discussão sobre possibilidades e outros pontos de vista, que mais ou menos consegui.Estou surpreso que ninguém tenha mencionado ConvertAll() até agora, pois essa é outra solução alternativa que usei, mas um pouco detalhada para os cenários em questão

@Roubar Ainda denovo e Sara

Obrigado, mas sinto que entendo os genéricos em toda a sua glória de contexto estático e entendi os problemas em jogo aqui.

O design real do nosso sistema e o uso de genéricos (e posso dizer isso sem qualquer preconceito, já que fui apenas um dos participantes do design) foi bem feito.Foi quando eu estava trabalhando com a API principal que encontrei situações em que estava no escopo errado para fazer algo simples; em vez disso, tive que lidar com elas de maneira um pouco menos elegante do que gostaria (tentando ser inteligente ou talvez preguiçoso - aceitarei qualquer um desses rótulos).

Minha aversão pelo que chamei de aglomeração é em grande parte porque precisamos fazer um loop em nosso conjunto de registros simplesmente para converter os objetos em seu valor base, o que pode ser um impacto no desempenho.

Acho que estava me perguntando se alguém já havia se deparado com isso em sua codificação antes e se alguém havia sido mais inteligente, ou pelo menos mais elegante, do que eu ao lidar com isso.

Foi útil?

Solução

Se você tem

class B : A
class C : A

E você tem

List<B> listB;
List<C> listC;

que você deseja tratar como uma lista do tipo pai

Então você deve usar

List<A> listA = listB.Cast<A>().Concat(listC.Cast<A>()).ToList()

Outras dicas

por que você tem uma coleção de MyObjects?Existe um motivo específico para você não ter uma lista?

No seu caso, MyObjectsA e MyObjectsB não possuem antecessor comum.A classe genérica é um modelo para diferente classes não são uma classe base comum.Se você deseja ter propriedades comuns em classes diferentes, use interfaces.Você não pode ligar Listar em um loop porque tem assinatura diferente em classes diferentes.Você pode criar um ToList que retorne objetos em vez de um tipo específico.

Provavelmente você ainda pode acessar o método ToList(), mas como não tem certeza do tipo, isso não funcionará?

foreach(var myObject in myObjectsList)
    foreach(var obj in myObject.ToList())
        //do something

É claro que isso só funcionará em C# 3.0.

Observe que o uso de var serve apenas para remover a exigência de saber que tipo as listas contêm;ao contrário dos comentários de Frank, tenho a ilusão de que var tornará a digitação dinâmica.

OK, estou confuso, o código a seguir funciona bem para mim (a curiosidade levou a melhor sobre mim!):

// Original Code Snipped for Brevity - See Edit History if Req'd

Ou perdi alguma coisa?

Atualização após resposta do OP

OK, agora estou realmente confuso..O que você está dizendo é que deseja obter uma lista de Digitado valores de uma lista genérica/abstrata?(as classes filhas, portanto, tornam-se irrelevantes).

Você não pode retornar uma lista digitada se os tipos forem filhos/implementadores de interface - eles não correspondem!É claro que você pode obter uma lista de itens de um tipo específico na lista abstrata, assim:

    public List<OfType> TypedList<OfType>() where OfType : IOtherObjects
    {
        List<OfType> rtn = new List<OfType>();

        foreach (IOtherObjects o in _objects)
        {
            Type objType = o.GetType();
            Type reqType = typeof(OfType);

            if (objType == reqType)
                rtn.Add((OfType)o);
        }

        return rtn;
    }

Se ainda estou errado aqui, você pode reformular sua pergunta?!(Não parece que eu seja o único que não tem certeza do que você quer dizer).Estou tentando estabelecer se há um mal-entendido sobre os genéricos de sua parte.

Outra atualização :D

Certo, então parece que você deseja/precisa da opção de obter a lista digitada ou a lista base, sim?

Isso faria com que sua classe abstrata ficasse assim - você pode usar ToList para obter o tipo concreto ou ToBaseList() para obter uma lista do tipo de interface.Isso deve funcionar em qualquer cenário que você tiver.Isso ajuda?

public abstract class MyObjects<T> where T : IOtherObjects
{
    List<T> _objects = new List<T>();

    public List<T> ToList()
    {
        return _objects;
    }

    public List<IOtherObjects> ToBaseList()
    {
        List<IOtherObjects> rtn = new List<IOtherObjects>();
        foreach (IOtherObjects o in _objects)
        {
            rtn.Add(o);
        }
        return rtn;
    }
}

Atualização nº 3

Não é realmente uma solução alternativa "desajeitada" (sem desrespeito) - essa é a única maneira de fazer isso.Acho que o maior problema aqui é um problema de design/grok.Você disse que tinha um problema, esse código resolve.Mas se você esperava fazer algo como:

public abstract class MyObjects<T> where T : IOtherObjects
{
    List<T> _objects = new List<T>();

    public List<IOtherObjects> Objects
    { get { return _objects; } }
}
#warning This won't compile, its for demo's sake.

E ser capaz de escolher os tipos que surgem disso, de que outra forma poderia faz você?!Tenho a sensação de que você realmente não entende qual é o objetivo dos genéricos e está tentando fazer com que eles façam algo para o qual não foram projetados!

Encontrei recentemente o

List<A>.Cast<B>().ToList<B>()

padrão.

Faz exatamente o que eu estava procurando,

Genéricos são usados ​​para verificações de tipo de tempo estático não despacho em tempo de execução.Use herança/interfaces para envio em tempo de execução, use genéricos para garantias de tipo em tempo de compilação.

interface IMyObjects : IEnumerable<IOtherObjects> {}
abstract class MyObjects<T> : IMyObjects where T : IOtherObjects {}

IEnumerable<IMyObjects> objs = ...;
foreach (IMyObjects mo in objs) {
    foreach (IOtherObjects oo in mo) {
        Console.WriteLine(oo);
    }
}

(Obviamente, prefiro enumeráveis ​​a listas.)

OU Basta usar uma linguagem dinâmica adequada como VB.:-)

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