Na sua encarnação original, ICommunicationObject : IDisposable. Sendo uma interface de marcação, achamos que seria útil notificar os usuários que eles deveriam liberar o objeto o mais rápido possível. Aí que os problemas começaram.
Até o Beta 1, nós tínhamos Dispose() == Abort(). Parte da razão era que o Dispose() deveria fazer o mínimo necessário para realizar a limpeza. Esse foi possivelmente a maior reclamação que ouvimos no Beta 1. Os usuários iriam colocar seus channels em um block using() e qualquer mensagem em cache esperando para ser enviada seria perdida. Transações não receberiam commit, sessões receberiam ACK etc.
Para atender este feedback nós mudamos o comportamento para que Dipose() ~= Close(). Nós sabíamos que lançar exceções causa problemas (algumas delas estão listadas neste tópico do newsgroup), então fizemos que o Dispose tentasse ser esperto. Isto é, se não estivéssemos no estado Opened, nós iríamos internamente chamar o Abort(). Isso sozinho tem seus próprios problemas, o principal sendo que você não pode inferir nada do ponto de vista de confiabilidade sobre o sistema. O Dispose ainda pode lançar exceções, mas ele não irá te notificar _sempre_ que alguma coisa errada aconteceu. Eventualmente tomamos a decisão de que precisávamos tirar o IDisposable do ICommunicationObject. Depois de muita discussão, o IDisposable permaneceu no ServiceHost e no ClientBase. A teoria era que para a maioria dos usuários, não há problemas de um método Dispose lançar exceções, pois eles preferem contar com a conveniência do bloco using() e da indicação que o objeto deve ser liberado o mais rápido possível. Você poderia questionar (e alguns de nós questionamos) que nós também deveríamos ter removido a interface destas duas classes, mas para bem ou para mal, é nesta situação que nós estamos hoje. É uma questão que nunca vai agradar a todos, então nos nossos exemplos do SDK nós precisamos apoiar melhores práticas, que são utilizar o paradigma try { Close } / catch { Abort }.