Por que implementar IEnumerable (T) se eu posso apenas definir ONE GetEnumerator?

Atualizar: Agradeço todos os comentários, que essencialmente constituíram oposição unânime. Embora todas as objeções levantadas sejam válidas, sinto que a unha definitiva no caixão foiA observação astuta de Ani que, finalmente, até o1 minúsculo O benefício que essa idéia ostensivamente ofereceu - a eliminação do código padrão - foi negado pelo fato de que a própria idéia exigiria suapróprio código padrão.

Então, sim, considere-me convencido: seria uma má ideia.

E só para salvar minha dignidade de alguma forma: eu poderia ter apostado no argumento, mas nunca fui realmente vendido com essa idéia - apenas curioso em ouvir o que os outros tinham a dizer sobre isso. Honesto.

Antes de descartar esta pergunta como absurda, peço que você considere o seguinte:

IEnumerable<T> herda de *IEnumerable, o que significa que qualquer tipo que implementeIEnumerable<T> geralmente deve implementarambos IEnumerable<T>.GetEnumerator e (explicitamente)IEnumerable.GetEnumerator. Isso basicamente equivale ao código padrão.Você podeforeach sobre qualquer tipo que tenha umGetEnumerator , desde que esse método retorne um objeto de algum tipo com umMoveNext método e umCurrent propriedade. Então, se seu tipo define1 método com a assinaturapublic IEnumerator<T> GetEnumerator(), é legal enumerá-lo usandoforeach.Claramente, há muito código por aí que requer oIEnumerable<T> interface - por exemplo, basicamente todos os métodos de extensão LINQ. Felizmente, para ir de um tipo que você podeforeach para umIEnumerable<T> é trivial usando a geração automática do iterador que o C # fornece viayield palavra-chave

Então, juntando tudo isso, tive uma ideia maluca: e se eu apenas definir minha própria interface que se parece com isso:

public interface IForEachable<T>
{
    IEnumerator<T> GetEnumerator();
}

Então sempre que defino um tipo que quero ser enumerável, implementoesta interface em vez deIEnumerable<T>, eliminando a necessidade de implementar doisGetEnumerator métodos (um explícito). Por exemplo:

class NaturalNumbers : IForEachable<int>
{
   public IEnumerator<int> GetEnumerator()
   {
       int i = 1;
       while (i < int.MaxValue)
       {
           yield return (i++);
       }
   }

   // Notice how I don't have to define a method like
   // IEnumerator IEnumerable.GetEnumerator().
}

Finalmente, para tornar esse tipo compatível com o código quefaz esperar oIEnumerable<T> interface, posso apenas definir um método de extensão para ir de qualquerIForEachable<T> para umIEnumerable<T> igual a:

public static class ForEachableExtensions
{
    public static IEnumerable<T> AsEnumerable<T>(this IForEachable<T> source)
    {
        foreach (T item in source)
        {
            yield return item;
        }
    }
}

Parece-me que fazer isso me permite projetar tipos que são utilizáveis de todas as formas como implementações deIEnumerable<T>, mas sem esse explícito traquinaIEnumerable.GetEnumerator implementação em cada um.

Por exemplo:

var numbers = new NaturalNumbers();

// I can foreach myself...
foreach (int x in numbers)
{
    if (x > 100)
        break;

    if (x % 2 != 0)
        continue;

    Console.WriteLine(x);
}

// Or I can treat this object as an IEnumerable<T> implementation
// if I want to...
var evenNumbers = from x in numbers.AsEnumerable()
                  where x % 2 == 0
                  select x;

foreach (int x in evenNumbers.TakeWhile(i => i <= 100))
{
    Console.WriteLine(x);
}

O que vocês acham dessa ideia? Estou perdendo algum motivo para isso ser um erro?

Sei que provavelmente parece uma solução excessivamente complexa para o que não é grande coisa para começar (duvido que alguémrealmente se preocupa muito em ter que definir explicitamente oIEnumerable interface); mas me veio à cabeça e não estou vendo nenhum problema óbvio que essa abordagem possa causar.

Em geral, se eu puder escrever uma quantidade moderada de códigouma vez para me poupar do trabalho de escrever uma pequena quantidade de códigomuitas vezes, para mim, vale a pena.

* Essa é a terminologia correta a ser usada? Sempre hesito em dizer que uma interface "herda de" outra, pois isso não parece capturar adequadamente o relacionamento entre elas. Mas talvez esteja certo.

questionAnswers(6)

yourAnswerToTheQuestion