Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Увлекательные моменты в C#

Anna | 17.06.2014 | нет комментариев
В этой статье мы коротко пройдемся по особенностям foreach. 1-й момент вы скорее каждого знаете, 2-й момент вы скорее каждого не знаете.

Предыдущая статья об особенностях C#.

1-й момент

На собеседованиях Зачастую спрашивают — «Что нужно сделать что бы ваш класс работал с foreach?». Результат на данный вопрос традиционно звучит так — «Реализовать IEnumerable». Результат данный верный, но не полный. В тезисе, этого результата на собеседовании довольно и я ни разу не встречал Дабы кто то считал его неправильным. На самом деле, foreach использует «утиную типизацию». Для того Дабы наш класс работал в foreach довольно иметь способ GetEnumerator возвращающий кое-что имеющее способ MoveNext и качество Current.

Запоминать эти способы не непременно, если подсунуть свой неверный класс в foreach компилятор Добросовестно подскажет чего реально не хватает в этом классе.

Примеры

Тестовый foreach:

class Program
{
	static void Main(string[] args)
	{
		var container = new Container();

		foreach (var item in container)
		{
		}
	}
}

Неверный контейнер:

public class Container
{
}

Оплошность компилятора:
foreach statement cannot operate on variables of type 'Container' because 'Container' does not contain a public definition for 'GetEnumerator'

Добавим способ GetEnumerator в контейнер и класс энумератора.

Верный контейнер:

public class Container
{
	public Enumerator GetEnumerator()
	{
		return new Enumerator();
	}
}

Неверный энумератор:

public class Enumerator
{
}

Оплошность компилятора:
foreach requires that the return type 'Enumerator' of 'Container.GetEnumerator()' must have a suitable public MoveNext method and public Current property

Добавим способ MoveNext и качество Current в энумератор.

Верный энумератор:

public class Enumerator
{
	public bool MoveNext()
	{
		return false;
	}

	public object Current
	{
		get { return null; }
	}
}

Сейчас компилятор все устраивает.

Примечание:
Качество Current может возвращать всякий тип, как ref type так и value type. Собственно это и стало поводом применения «утиной типизации», во времена когда не было generics, для избежания непотребныхboxing и unboxing.

2-й момент

На собеседовании встречаются вопросы про IDisposable и помимо всеобщих вопросов про ручное управление источниками есть вопрос про то, в каких случаях компилятор может механически вызывать способ Dispose. Результат все мы знаем — Dispose вызывается механически при применении оператора using(). Результат данный верный, но неполный! Способ Dispose может вызывается в 2-х случаях, помимо using(), он вызывается в foreach для энумератора, если энумератор реализует IDisposable.

Примеры

Энумератор с Dispose:

using System;

public class Enumerator : IDisposable
{
	public bool MoveNext()
	{
		return false;
	}

	public object Current
	{
		get { return null; }
	}

	public void Dispose()
	{
		Console.WriteLine("Dispose");
	}
}

Сейчас при запуске примера мы увидим строчку «Dispose» в консоли.

Для тех кому увлекательно, вот код тот, что генерит компилятор для нашего случая:

Container container = new Container();
Enumerator enumerator = container.GetEnumerator();
try
{
	while (enumerator.MoveNext())
	{
		var element = enumerator.Current;
		// содержимое foreach
	}
}
finally
{
	IDisposable disposable = enumerator as IDisposable;
	if (disposable != null)
		disposable.Dispose();
}

Каждому спасибо за внимание!

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB