.method public hidebysig instance class [mscorlib] System.Collections.IEnumerator GetEnumerator() cil managed {
…
newobj instance void CustomEnumeratorWithYield.Garage/ '‹GetEnumerator›d__0
…
} // end of method Garage::GetEnumerator
Явно, что от предложенного здесь определения метода итератора мы не получим большой пользы, поскольку наш тип Garage изначально реализовывал GetEnumerator(), ссылаясь на внутренний тип System.Array. Но синтаксис итератора C# может сэкономить немало времени при построении более "экзотических" пользовательских контейнеров (например, бинарных деревьев), где приходится вручную реализовать интерфейсы IEnumerator и IEnumerable. В любом случае программный код вызывающей стороны при взаимодействии с методом итератора с использованием foreach оказывается одинаковым.
static void Main(string[] args) {
Console.WriteLine("***** Забавы с методами итератора *****\n");
Garage carLot = new Garage();
foreach (Car с in carLot) {
Console.WriteLine("{0} имеет скорость {1} км/ч", с.PetName, с.CurrrSpeed);
}
Console.ReadLine();
}
Исходный код
. Проект CustomEnumeratorWifhYield размещен в подкаталоге, соответствующем главе 7.Создание клонируемых объектов (ICloneable)
Вы, должно быть, помните из главы 3, что System.Object определяет член с именем MemberwiseClone(). Указанный метод используется для получения
// Класс Point.
public class Point {
// Открыты для простоты.
public int x, у;
public Point(int x, int y) { this.x = x; this.у = у; }
public Point(){}
// Переопределение Object.ToString().
public override string ToString() { return string.Format("X = {0}; Y = {1}", x, у); }
}
С учетом того, что вы уже знаете о ссылочных типах и типах, характеризуемых значениями (см. главу 3), вы должны понимать, что в результате присваивания одной ссылочной переменной другой получаются две ссылки, указывающие на один и тот же объект в памяти. Поэтому следующее присваивание дает две ссылки на один и тот же объект Point в динамической памяти, и модификации любой из этих ссылок будут влиять на этот объект.
static void Main(string[] args) {
// Две ссылки на один и тот же объект!
Point p1 = new Point(50, 50);
Point p2 = p1;
р2.х = 0;
Console.WriteLine(p1);
Console.WriteLine(p2);
}
Чтобы обеспечить пользовательскому типу возможность возвращать копию этого типа вызывающей стороне, можно реализовать стандартный интерфейс ICloneable. Этот интерфейс определяет единственный метод с именем Clone().
public interface ICloneable
object Clone();
}
Очевидно, что реализация метода Clone() будет зависеть от объекта. Но базовые функциональные возможности оказываются одинаковыми: это копирование значений членов-переменных в новый экземпляр объекта и возвращение этого экземпляра пользователю. В качестве иллюстрации рассмотрите следующую модификацию класса Point.
// Теперь Point поддерживает клонирование.
public class Point: ICloneable
public int x, y;
public Point(){}
public Point (int x, int y) { this.x = x; this.у = у; }
// Возвращение копии данного объекта.
public object Clone() { return new Point(this.x, this.y); }
public override string ToString() { return String.Format("X = {0}; Y = {1}", x, у); }
}
С помощью указанного подхода можно создавать точные и независимые копии типа Point, как показано в следующем фрагменте программного кода.
static void Main (string[] args) {