Eu me deparei com esta situação. De fato, como apontado em outro lugar, o BCL tem tais instâncias ... tentarei fornecer melhores exemplos e fornecer algumas justificativas:
Quando você já possui uma interface que mantém por motivos de compatibilidade e ...
A interface contém membros obsoletos ou descartados. Por exemplo BlockingCollection<T>.ICollection.SyncRoot
(entre outros), embora ICollection.SyncRoot
não seja obsoleto, ele será lançado NotSupportedException
.
A interface contém membros documentados para serem opcionais e que a implementação pode gerar a exceção. Por exemplo, no MSDN sobre IEnumerator.Reset
isso, diz:
O método Reset é fornecido para interoperabilidade COM. Não precisa necessariamente ser implementado; em vez disso, o implementador pode simplesmente lançar uma NotSupportedException.
Por um erro no design da interface, deveria ter sido mais de uma interface em primeiro lugar. É um padrão comum na BCL implementar versões somente leitura de contêineres NotSupportedException
. Eu já fiz isso, é o que se espera agora ... faço ICollection<T>.IsReadOnly
retornotrue
para que você possa dizer a eles. O design correto seria ter uma versão legível da interface e, em seguida, a interface completa herda disso.
Não há interface melhor para usar. Por exemplo, eu tenho uma classe que permite acessar itens por índice, verificar se ele contém um item e em qual índice, tem algum tamanho, você pode copiá-lo para uma matriz ... parece um trabalho, IList<T>
mas minha classe tem um tamanho fixo e não suporta adicionar nem remover, por isso funciona mais como uma matriz do que como uma lista. Mas não há IArray<T>
no BCL .
A interface pertence a uma API que é portada para várias plataformas e, na implementação de uma plataforma específica, algumas partes dela não são suportadas. Idealmente, haveria alguma maneira de detectá-lo, para que o código portátil que usa essa API possa decidir o que quer ou não chamar essas partes ... mas se você chamá-las, é totalmente apropriado obtê-las NotSupportedException
. Isso é particularmente verdade, se for uma porta para uma nova plataforma que não estava prevista no design original.
Considere também por que não é suportado?
Às vezes InvalidOperationException
é uma opção melhor. Por exemplo, mais uma maneira de adicionar polimorfismo em uma classe é ter várias implementações de uma interface interna e seu código está escolhendo qual instanciar, dependendo dos parâmetros fornecidos no construtor da classe. [Isso é particularmente útil se você souber que o conjunto de opções é fixo e não deseja permitir que classes de terceiros sejam introduzidas por injeção de dependência.] Fiz isso para suportar o ThreadLocal porque a implementação de rastreamento e não rastreamento é distante demais, e o que ThreadLocal.Values
lança na implementação sem rastreamento?InvalidOperationException
mesmo assim, não depende do estado do objeto. Nesse caso, eu mesmo apresentei a classe e sabia que esse método tinha que ser implementado apenas lançando uma exceção.
Às vezes, um valor padrão faz sentido. Por exemplo, no ICollection<T>.IsReadOnly
mencionado acima, faz sentido retornar apenas "verdadeiro" ou "falso", dependendo do caso. Então ... qual é a semântica IFoo.Bar
? talvez haja algum valor padrão sensato para retornar.
Adendo: se você está no controle da interface (e não precisa ficar com ela por compatibilidade), não deve haver um caso em que você precise jogar NotSupportedException
. No entanto, pode ser necessário dividir a interface em duas ou mais interfaces menores para se adequar ao seu caso, o que pode levar à "poluição" em situações extremas.