Правильный ответ на этот вопрос требует определенных усилий, поскольку короткий ответ («нет») может вводить в заблуждение.
Является ли описание API явно скажем, вы должны позвонить по номеру EndPeek()
за каждый звонок до BeginPeek()
? Не в любой теме, я мог бы найти, и не только в том, что, как представляется, утверждать обратное here:
Чтобы использовать BeginPeek
, создать обработчик событий, который обрабатывает результаты асинхронной операции, и связать его с вашим событие делегат. BeginPeek
инициирует операцию асинхронного просмотра; MessageQueue
уведомляется о получении сообщения PeekCompleted
, когда сообщение поступает в очередь. MessageQueue
может затем получить доступ к сообщению по телефону EndPeek(IAsyncResult)
или путем получения результата с использованием PeekCompletedEventArgs
.
(выделено мной). Это, кажется, говорят, что вы можете использовать либо .EndPeek()
или просто непосредственно получить сообщение от арг событий без обязательств позвонить .EndPeek()
.
Хорошо, соответствует ли мандат на выполнение, который вы называете .EndPeek()
, чтобы все работало правильно? По крайней мере для реализации System.Messaging
в .NET 4.0 ответ отрицательный. Когда вы вызываете .BeginPeek()
, асинхронная операция распределяется и обратный вызов регистрируется для завершения. Неуправляемые ресурсы, связанные с этой операцией, частично очищаются в этом обратном вызове, и только тогда вызываемый обработчик события. .EndPeek()
фактически не выполняет никакой очистки - он просто ждет завершения операции, если он еще не установлен, проверяет наличие ошибок и возвращает сообщение. Так что действительно верно, что вы можете либо позвонить .EndPeek()
, либо просто получить доступ к сообщению от событий args или ничего не делать - все будет работать так же плохо.
Плохо, да - обратите внимание, что я сказал «частично очищен». Реализация MessageQueue
имеет проблему в том, что она выделяет ManualResetEvent
для каждой асинхронной операции, но никогда не использует ее, оставляя это полностью до сборщика мусора - что-то, что разработчики .NET часто издеваются, но, конечно же, собственные разработчики Microsoft aren Совершенно. Я не тестировал, является ли утечка OverlappedData
, описанная в this question, по-прежнему актуальной и не является очевидной из источника, но это меня не удивит.
В API есть другие предупреждающие знаки, что его реализация может оставить желать лучшие, наиболее заметно, что она не соответствует установленной .Begin...()
/.End...()
шаблона для асинхронных операций, но вводит обработчик событий в середине, создавая странный гибрид I» я никогда больше не увижу. Тогда есть очень сомнительное решение о наследовании класса Message
от Component
, что добавляет значительные накладные расходы для каждого экземпляра и ставит вопрос о том, когда и как его следует утилизировать ... в целом, а не в лучшей работе Microsoft.
Теперь, значит ли это, что вы не «обязаны» позвонить .EndPeek()
? Да, в том смысле, что называть это или не называть это не имеет никакого функционального различия в отношении очистки или правильности ресурсов. Но со всем, что сказал, мой совет по-прежнему назовите его в любом случае. Зачем? Поскольку любой, кто знаком с тем, как работает асинхронный рабочий шаблон в других классах .NET, ожидает, что вызов будет там, и не помещать его там, выглядит как ошибка, которая может привести к утечке ресурсов. Если есть проблема с приложением, такой человек может разумно потратить некоторое бесплодное усилие на «проблемный код», которого нет. Учитывая, что звонок .EndPeek()
имеет незначительные накладные расходы по сравнению с остальными машинами, я бы сказал, что сбережения в программиста удивляет больше, чем компенсирует затраты. Возможная альтернатива заключается в том, чтобы вставить комментарий вместо этого, объясняя, почему вы не звоните .EndPeek()
- но, по всей вероятности, это все еще требует больше циклов программирования, чем просто называть его.
Теоретически, еще одна причина для его вызова состоит в том, что семантика API может измениться в будущем, чтобы сделать звонок .EndPeek()
необходимым; на практике это маловероятно, потому что Microsoft традиционно неохотно делает такие изменения (код, который ранее и разумно не вызывал .EndPeek()
, перестанет работать), и существующая реализация уже противоречит сложившейся практике.
Есть ли какие-либо убедительные * причины * для того, чтобы не вызывать '.EndPeek()'? Если вам не нужен результат '.EndPeek()', вы можете отказаться от него, но не называть его вообще - это почти наверняка плохая идея - вы, по сути, занимаетесь '.BeginPeek()' not выделяя любые неуправляемые ресурсы, которые '.EndPeek()' должен выпустить. Даже если это правда сейчас, кто говорит, что следующий выпуск не нарушит это предположение? –
Боковое примечание: pleinolijf, ваше сообщение читается как «мой код выглядит некорректно, любой шанс, что он будет работать надежно». Лично я бы не делал этого независимо от возможности правильной работы кода - время, потраченное на поиск/исправление отсутствующего вызова EndXXXX всеми будущими читателями кода, скорее всего, выберет любую «экономию», которую вы сделаете. –
Справедливые точки, вы оба. И это, по сути, то, о чем я спрашиваю: безопасно ли вы незывать EndPeek? Действительно ли BeginPeek выделяет ресурсы? Это то, что мне непонятно, хотя, очевидно, именование методов действительно предполагает это. Я ищу, это факты, а не предположения. – pleinolijf