Pergunta

Estou desenvolvendo uma aplicação onde eu a necessidade de invocar um método de uma classe genérica e não se preocupam com a instâncias tipo real. Algo como o seguinte código Java:

public class Item<T>{
  private T item;

  public doSomething(){...}
}

...
public void processItems(Item<?>[] items){
 for(Item<?> item : items)
   item.doSomething();
}

Na época, eu estava em uma pressa, então eu resolvido meu problema, definindo uma interface com os métodos que eu precisava para invocar e fez a classe genérica implementá-lo.

public interface IItem  
{
   void doSomething();
}

public class Item<T> : IItem {
  private T item;

  public void doSomething(){...}
}

...
public void processItems(IItem[] items)
{
 foreach(IItem item in items)
   item.doSomething();
}

Esta solução funciona bem, mas eu gostaria de saber o que é a maneira correta para obter o mesmo comportamento.

EDIT:

Esqueci-me de referir que o chamador de processItems não conhece os tipos reais. Na verdade, a idéia era que o array passado como argumento para processItems poderia conter tipos misturados. Desde que não é possível ter uma matriz como em .Net, usando uma classe base genérico não ou interface parece ser o único caminho.

Foi útil?

Solução

O caminho normal para fazer isso seria fazer o método genérico:

public void ProcessItems<T>(Item<T>[] items) {
  foreach(Item<T> item in items)
    item.DoSomething();
}

Assumindo que o chamador conhece o tipo, tipo de inferência deve significar que eles não têm que especificá-lo explicitamente. Por exemplo:

Item<int> items = new Item<int>(); // And then populate...
processor.ProcessItems(items);

Dito isto, criando uma interface não genérica especificando as operações do tipo agnóstico pode ser útil também. É muito vai depender do seu caso de uso exato.

Outras dicas

Eu vejo que você só deseja chamar algum método sem parâmetros ... já existe um contrato para que:. Action

public void processItems(IEnumerable<Action> actions)
{
  foreach(Action t in actions)
    t();
}

Cliente:

List<Animal> zoo = GetZoo();
List<Action> thingsToDo = new List<Action>();
//
thingsToDo.AddRange(zoo
  .OfType<Elephant>()
  .Select<Elephant, Action>(e => e.Trumpet));
thingsToDo.AddRange(zoo
  .OfType<Lion>()
  .Select<Lion, Action>(l => l.Roar));
thingsToDo.AddRange(zoo
  .OfType<Monkey>()
  .Select<Monkey, Action>(m => m.ThrowPoo));
//
processItems(thingsToDo);

Não há nenhuma maneira você pode omitir Tipo Parâmetros na implementação genérica .NET; isso é por design. Na verdade, isso só pode ser alcançado em Java por causa de sua implementação com base tipo-apagamento-.

Você só pode usar uma interface de base não-genérico (pense IEnumerable<T> e IEnumerable).

No seguimento pós de Jon. tornando o método genérico (um modelo) nega a exigência para esse tipo de funcionalidade (usando ). Você sempre pode alimentar um tipo em uma classe / função genérica e para os casos em que você não sabe que tipo você precisa, você pode fazer a ofender método / classe genérica, bem ... em última análise, o usuário tem que fornecer um tipo ao chamar tal função ou usar uma classe genérica, para o código para ser capaz de compilar ... caso contrário, você vai ter alguns erros do compilador.

Eu estive lutando com o mesmo problema quando se tratava de coisas portando a partir do Java onde eu tive construções como

if (o instanceof Collection<?>) doSoemthing((Collection<?>)o);

Felizmente acontece que um ICollection genérico é também um ICollection não-genéricos e se alguém precisa de tratar os elementos nele como objetos puros, ainda é possível:

if (o is ICollection) DoSomething((ICollection)o);

Dessa forma, uma vez que não se preocupam com o tipo real de elementos na coleção todos nós chegar aqui são objetos. Uma nota aqui:. Se a coleção estava segurando tipos primitivos (int ou bytes por exemplo), então autoboxing chutes no qual pode introduzir penalidade de desempenho

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