Существует ли канонический способ «исправить» «динамический» IEnumerable?

IEnumerable не гарантирует, что повторное перечисление даст тот же результат. Фактически, довольно легко создать пример, в котором myEnumerable.First () возвращает разные значения при двойном выполнении:

class A {
    public A(string value) { Value = value; }
    public string Value {get; set; } 
}

static IEnumerable getFixedIEnumerable() {
    return new A[] { new A("Hello"), new A("World") };
}

static IEnumerable getDynamicIEnumerable() {
    yield return new A("Hello");
    yield return new A("World");
}

static void Main(string[] args)
{
    IEnumerable fix = getFixedIEnumerable();
    IEnumerable dyn = getDynamicIEnumerable();

    Console.WriteLine(fix.First() == fix.First()); // true
    Console.WriteLine(dyn.First() == dyn.First()); // false
}

Это не просто академический пример: использование популярного из ... in ... select new A (...) создаст именно такую ​​ситуацию. Это может привести к неожиданному поведению:

fix.First().Value = "NEW";
Console.WriteLine(fix.First().Value); // prints NEW

dyn.First().Value = "NEW";
Console.WriteLine(dyn.First().Value); // prints Hello

Я понимаю, почему это происходит. Я также знаю, что это можно исправить, выполнив ToList () в Enumerable или переопределив == для класса A . Это не мой вопрос.

Возникает вопрос: когда вы пишете метод, который принимает произвольный IEnumerable, и вам нужно свойство, согласно которому последовательность вычисляется только один раз (а затем ссылки становятся «фиксированными»), каков канонический способ сделать это? ToList () , похоже, используется в основном, но если источник уже исправлен (например, если источник является массивом), ссылки копируются в список (без необходимости, поскольку все, что мне нужно, это фиксированная собственность). Есть ли что-то более подходящее или ToList () «каноническое» решение этой проблемы?

6
задан Heinzi 9 February 2012 в 09:33
поделиться