- Событие нельзя объявить свойством, только полем. Однако событие поддерживает определение своих методов подписки и отписки (add и remove) в стиле свойств.
- Реализация подписки и отписки на событие потокобезопасна (речь идёт о штатных методах add и remove).
- Полю события нельзя присвоить null вне другого класса. Вообще, стороннему коду нельзя ничего сделать с полем события кроме как подписаться или отписаться. Для этого используются операторы += и -=, которые транслируются в вызов add и remove. Оператор = к событиям не применим.
- Запускать событие напрямую можно только в том классе, в котором оно объявлено. Даже в потомках нельзя. Однако это можно сделать через метод-обёртку.
Программирование
понедельник, 3 марта 2014 г.
Сравнение: event vs delegate
пятница, 28 февраля 2014 г.
Ошибка в переводном 4-м издании "CLR via C#" Рихтера
В примере кода, который находится в разделе "Уведомление о событии, безопасное в отношении потоков" (с. 291), использован устаревший метод Thread.VolatileRead() вместо Volatile.Read().
В оригинальном издании всё правильно — везде используется Volatile.Read(). В разделе упоминания этих методов чередуются, так что судя по всему это результат "недоправки" листингов с предыдущих изданий. Больше нигде в книге Thread.VolatileRead() не упоминается. Про Thread.VolatileRead() и Volatile.Read() можно начать читать отсюда.
вторник, 11 февраля 2014 г.
Неработающий XAML-дизайнер Visual Studio 2013 в проекте для Windows Store
При попытке запуска дизайнера XAML-страницы проекта для Windows Store получаю такое исключение:
System.Runtime.InteropServices.COMException Это приложение не поддерживает указанный контракт или не установлено. (Exception from HRESULT: 0x80270254)
Для информации: среда разработки Visual Studio 2013 Ultimate установлена на Windows 8.1 Pro x64.
Это ошибка появляется при открытии дизайнером XAML-страницы именно для Windows Store. В обычном WPF-проекте ошибки нет, в проекте для Windows Phone — тоже. Начал гуглить. Чтение форумов не помогло. Сделал Repair установки — ошибка не исчезла. Видимо, дело не в повреждённых файлах или настройках.
Моя рабочая учётная запись (в которую я обычно загружаюсь) имеет права рядового пользователя Windows 8. Среду Visual Studio 2013 я привык запускать с правами администратора. Например, чтобы иметь возможность присоединяться к процессу IIS для отладки.
По опыту знаю, что запуск программы с правами администратора — это не одно и тоже, что и запуск программы в загруженной учётной записи администратора. Поэтому решил загрузиться в учётную запись администратора и открыть дизайнер там. Дизайнер открылся без ошибок. Это меня расстроило, т. к. мне не хотелось всякий раз загружаться как администратор, когда мне необходимо программировать. На всякий случай решил попробовать открыть дизайнер в студии, запущенной в рабочей учётной записи без дополнительных привелегий. Дизайнер открылся без ошибки! Такое поведение для меня выглядит странным. Другого решения я не нашёл. Установка Update 1 для VS 2013 не помогла. Если у кого-то в такой же ситуации дизайнер работает без ошибок, был бы признателен за отклик.
понедельник, 10 февраля 2014 г.
Доступ к непубличным экземплярным полям класса
class PrivateFieldsAccess
{
private int privateField;
protected int protectedField;
public PrivateFieldsAccess(PrivateFieldsAccess instance)
{
privateField = instance.privateField;
protectedField = instance.protectedField;
}
}
Модификаторы доступа определяют доступ к членам класса, а не экземпляра. Другими словами, ограничение доступа к членам класса служит для инкапсуляции и снижения зависимости между кусками кода, а не снижения зависимости объектов в памяти во время выполнения.
пятница, 19 апреля 2013 г.
Ловушки при использовании Response.Filter
ASP.NET позволяет через свойство HttpResponse.Filter выполнять манипуляции с контентом перед отправкой его клиенту. Под контентом понимается html-разметка, css-стиль, js-код и вообще любые данные, отправляемые веб-сервером в ответ на запрос. Для чего это нужно? Например, для замены в теле ответа одного текста на другой. Подробно расписывать как это делать я не буду, а покажу очень важные особенности, которые необходимо учитывать при реализации продобного рода фильтров.
Первая ловушка — отдаваемый сервером контент разбивается на порции. Приведу типичный код, встречающийся на просторах интернета, который заменяет текст:
public class HtmlFilter : Stream
{
// Второстепенный код пропущен.
// Основной метод, производящий замену текста перед записью в поток.
public override void Write(byte[] buffer, int offset, int count)
{
Encoding encoding = HttpContext.Current.Response.ContentEncoding;
string s = encoding.GetString(buffer);
s = Regex.Replace(s, pattern, replacement);
byte[] outData = encoding.GetBytes(s);
_baseStream.Write(outData, 0, outData.Length);
}
}
Чем примечателен этот код? Тем, что он неправильный. Контент разбивается на порции, и эти порции записываются в поток по отдельности — метод Write() вызывается несколько раз. Это значит, что иногда в отфильтрованном контенте будут присутствовать незаменённые экземпляры искомого текста, которым "посчастливилось" попасть на границы порций, а значит Regex просто не найдёт и не заменит их. Самое плохое в этой ошибке то, что она выглядит как случайная, её очень сложно воспроизвести. Вероятность её проявления прямо пропорционально величине заменяемого текста (pattern'а). Чем он больше, тем вероятней то, что он окажется на границе порций контента. В моём случае заменяемый текст являлся частью URL, и мне даже удалось увидеть один "неправильный" URL.
Окей, как же тогда правильно заменять текст в контенте? Основной принцип — склеивать порции, потом анализировать их вместе, и после этого писать в поток и отсылать. На эту тему есть замечательный пост Рика Страла (Rick Strahl). Он реализовал удобный класс-фильтр, который решает эту проблему.
Вторая ловушка существует при фильтрации статического контента. Если включено сжатие статических файлов, IIS помещает сжатые статические оригинальные файлы в свой кэш. При последующих запросах IIS сразу отдаст файл из кэша, минуя потоковый фильтр. Выглядит это так: при первом запросе к статическому файлу возвращается содержимое файла с произведённой обработкой. При дальнейших запросах возвращается уже оригинальное содержимое, потому что взято оно из кэша. Побороть это можно отключением сжатия статического контента.
четверг, 20 декабря 2012 г.
.NET Framework 4.5 — это лишь апдейт для 4-й версии
- 4.5 ставит себя в каталог v4.0.30319, предназначенный для 4-й версии. В MSDN написано, что "сборки заменяются" (the assemblies are replaced).
- Этот пункт вытекает из предыдущего — на компьютере не могут быть одновременно установлены обе версии, только одна из них. Это принципиально отличается от предыдущих выпусков, когда версии 1.0, 1.1, 2.0, 3.0 и 3.5 живут на компьютере бок о бок. Чтобы вернуться к 4-й версии, 4.5 необходимо полностью удалить.
-
Версии файлов сборок отличаются лишь последней группой цифр:
- Новые ключевые слова C# — async и await — можно использовать и в 4-й версии при установке соответствующего обновления.
- Пожно скомпилировать программу для версии 4.5, и она будет работать исправно в среде 4-й версии, но до тех пор, пока не попытается воспользоваться особенностями, присущие только версии 4.5.
- В IIS нельзя выбрать среду исполнения ".NET Framework 4.5" у пула приложений — только 2.0 или 4.0.
Источники
- http://www.west-wind.com/weblog/posts/2012/Mar/13/NET-45-is-an-inplace-replacement-for-NET-40 — наиболее полное изложение по теме
- http://msdn.microsoft.com/en-us/library/5a4x27ek.aspx
вторник, 25 сентября 2012 г.
Сравнение: const vs readonly
| Аспект | const | readonly |
| Место инициализации | Только при объявлении поля. | При объявлении поля, в конструкторах экземпляра, в статическом конструкторе. |
| Время инициализация | При компиляции. | При создании экземпляра класса или при обращении к статическим членам класса. |
| Поддерживаемые типы | Boolean, Char, Byte, SByte, Intl6, UIntl6, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, String и enum. Использовать ссылочные типы как константы не имеет смысла, т. к. единственное допустимое начальное значение таких констант — null. Исключение — тип String. | Любой тип. |
| Способ хранения | Хранится в метаданных сборки. Везде, где встречается константа, компилятор вставляет вместо неё само значение. В период выполнения память для неё не выделяется. | Хранится как обычное (instance) поле с выделением памяти в период выполнения. |
| Разделение между сборками | Везде, где встречается константа, определённая в другой сборке, компилятор вставляет вместо неё само значение из сборки. После компиляции, сборка с константой более не требуется для выполнения приложения (при условии, что используется только константа). Если константа будет изменена, то для использования нового значения в других сборках потребуется их перекомпиляция. | Разделяется как обычное поле. Сборка с reaonly полем должна присутствовать в списке ссылок у сборок-клиентов. |
Источники
- http://msdn.microsoft.com/ru-ru/library/acdd6hb7.aspx.
- Дж. Рихтер. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.0 на языке C#. – С. 191.