Я, как вы знаете, пишу не только статьи в свой блог, но и код. Программный код. Поэтому, меня зачастую интересуют вопросы, которые нормальным людям в голову и не лезут. Суть сегодняшней дилеммы очень простая – хорошо ли генерировать исключительные ситуации из конструктора? Это скорее философский или этический вопрос, нежели сложная техническая задача. И все же.
Конструкторы не возвращают каких-либо значений, поэтому было бы здорово сгенерировать ошибку, в случае, если объект не может быть создан. И таким образом, оповестить всех что этот объект использовать дальше нельзя. Уже слышу протестующие крики в свой адрес: “…Конструкторы предназначены для простых операций типа инициализации объекта…” или “…Лучше после попытки создания объекта проверить его на null…”.
А я не согласен с этим!
Когда мы передаем в конструктор некие параметры, мы обязаны проверить их на валидность. А как вы сообщите об “испорченном” параметре? С помощью null? Что? Опять протесты?
“…А давайте оставим конструктор пустым и добавим метод Initialize, который и вернет нам необходимый код состояния инициализации объекта…”
Хм, а конструкторы тогда зачем? Для тех, кто все еще сомневается в моих доводах, советую прочесть презентацию Bjarne Stroustrupsa (он настолько крутой, что придумал С++) об “Standard-Library Exception Safety”. И там, все вышесказанное, размазано по 36 страницам. Поэтому генерировать исключительные ситуации в конструкторе – это нормально (особенно, если вы исповедуете RAII).
В C#.NET есть еще одна приятная особенность – finalizer вызовится даже в случае ошибки в конструкторе и ресурсы будут освобождены корректно. Кстати и в самом .NET Framework многие базовые классы генерируют исключительные ситуации из конструктора, например Guid, DateTime, Queue, FileStream и другие.
А вы генерируете ошибки в конструкторах?
Один из моментов, который необходимо учесть при работе с Entity Framework - это как работать с таблицами без первичных ключей. По умолчанию сущность такой таблицы(proxy-класс) будет мэпится не к физической модели таблицы, а к так называемому Defining Query.Чтоб очень это мешало - так нет, но обновлять/изменять данные в этой таблице сразу после генерации класса вы не можете. Да и дизайнер не показывает, что это таблица только на посмотреть (и это не просто слова, а намек тем, кто этот дизайнер пишет). Поэтому вы получите ошибку времени выполнения Unable to update the EntitySet 'Events' because it has a
DefiningQuery and no <DeleteFunction> element exists in the
<ModificationFunctionMapping> element to support the current
operation.
И это еще не все проблемы на которые вы можете тут наступить. Во время генерации вашего прокси-класса Entity Framework пометит все хорошие поля как часть Entity Key (откровенно говоря это все не nullable и не binary поля). Правда надо отдать должное EF - во время генерации прокси-класса из базы данных, вы можете видеть такое предупреждение: "The table/view 'DemoTable' does not have a primary key defined. The key
has been inferred and the definition was created as a read-only
table/view." Для починить это нужно добавить в поле вашей таблицы первичный ключ, а затем обновить модель из базы данных. После нужно будет ручками подправить ключевые поля в вашей сущности(Entity). Есть еще одна возможность обновлять данные в таблице без первичного ключа - промэпить хранимые процедуры на удаление и модификацию данных.
А вообще работы много, писать некогда, но все равно буду - хоть мало, так смачно.
Я уже писал о фичах последнего решарпера, а сейчас хочу поговорить о будующих фичах этого замечательного продукта. Разработчики обещают оптимизировать работу с памятью и увеличить скорость работы продукта. В дополнение к этим улучшениям будет реализовано следующее:
- Будут добавлены новые способы/методы рефакторинга кода. Большинство из них будут из inline "семейства".
- Планируется расширить функционал для работы с соглашениями по кодированию. "Мы не собираемся реализовывать функционал AgentSmith плагина, мы лишь хотим избавить наших пользователей от рутиной работы" - заявляют разработчики.
- Также будет добавлена новая фича под названием Visual Build, целью которой будет отображать процесс сборки проекта в студии. Фича была заявлена как платформа для будующей фичи по оптимизации процесса сборки.
- Ожидается полная поддержка Visual Basic 9 с его анонимными функциями и XML литералами.
И не забывайте, что все вышеописанное возможно благодаря вашим feedback'ам и даже идеям.
Ссылки по теме:
Прорезь в копилке с идеями (бросать только идеи на $1 млн.)
База знаний Решарпера
Официальный сайт Resharper'a
Ребята из JetBrains выпустили новый решарпер и теперь он доступен для "покупки" и скачивания с их официального сайта.
Пожалуй самая интересная фича нового решарпера - поддержка C# 3.0 и LINQ. Но первая вещь которую я заметил, это "Reformat" переименовали в "Cleanup Code", и поначалу, это сбивало с толку. Зато сейчас эта фича поддерживает профайлы, т.е. различные профайлы могут делать различные "очистки кода": переход к авто-свойствам, использование анонимных типов, формирование readonly полей, если это возможно и многое другое.
Но единственное, что у меня пока не получилось - это редактирование стандартных профайлов.
Следующее, на что я обратил внимание это инициализация объектов, к примеру если я напишу
Task t =
new Task();
t.Name = "Test";
То решарпер мне предложит поступить следующим образом:
Task t =
new Task {Name = "Test"};
Аналогичным образом решарпер предлагает использовать implicit type variable:
Решарпер советует использовать var везде, где это возможно. Такое решение далеко не всегда оправдано, поэтому я отключил этот функционал.

Зачатки JetBrains.Annotation были еще в решарпере версии 2.5. Если помните был такой "Null Reference Analysis", который оповещал разработчика о возможных NullReferenceException в коде. Чтобы избежать такого анализа разработчики добавляли к свойствам, атрибуты NotNull или CanBeNull, которые решарпер позже использовал для инициализации состояния переменных. В новой же версии количество таких атрибутов значительно увеличилось. Скажем, если вы хотите явно указать, что ваш строковый параметр будет обрабатываться с помощью string.Format, то можете написать следующее
[StringFormatMethod("key")]
public void Put(
string key,
params object[] args) { ... }
После чего вызвав эту функцию
Put("testing {0}, {1}, {2}", 1, 2);
решарпер подскажет, что переменная для аргумента {2} отсутствует. Но использования этой фичи требует включения нескольких JetBrain библиотек в ваш проект, что несколько смущает...
Довольно удобным стал CamelHumps Completion, позоволяющий писать лишь заглавные буквы ключевых слов, названий классов, переменных:
После нажатия магического сочетания клавиш
<Ctrl-Shift-Enter>, получаем
if (CodeViewManager.Instance.SupportsView(StandardCodeViews.FindUsages))
{
}
Как я уже упоминал, теперь решарпер полностью поддерживает C# 3.0 и LINQ, что не может не радовать.
Recent Edits позволяет быстро получить доступ к недавно редактируемым участкам кода (CTRL + "-" уже просто достал!):
И в заключение, хочу добавить, что создатели решарпера клянутся, что он стал быстрее, особенно в обработке ASP.NET кода.
Полезные ссылки:
Официальный сайт решарпера
Новые фичи четвертого решарпера
Скачать Resharper 4.0
Купить Resharper 4.0
Блог Ильи Рыженкова, продукт-менеджера компании JetBrains
Речь пойдет о коллекциях IDictionary. Не знаю как вам, но мне надоела постоянная проверка .ContainsKey(), каждый раз, когда я хотел получить значение из словаря.
Dictionary<string, string> dict;
if (dict.ContainsKey("key"))
value = dict["key"];
else
value = "defaultValue";
Поэтому мне пришлось реализовать такую вот нехитрую обертку:
public static class MyExtensions
{
public static TValue GetValue<TKey, TValue>(
this IDictionary<TKey, TValue> source, TKey key, TValue defaultValue)
{
if (source.ContainsKey(key))
return source[key];
else
return defaultValue;
}
}
И теперь получить значение стало намного проще:
value = dict.GetValue("key", "defaultValue");