Eu entendo como trabalhar com interfaces e implementação explícita de interfaces em C #, mas fiquei pensando se é considerado uma forma incorreta ocultar certos membros que não seriam usados com freqüência. Por exemplo:
public interface IMyInterface
{
int SomeValue { get; set; }
int AnotherValue { get; set; }
bool SomeFlag { get; set; }
event EventHandler SomeValueChanged;
event EventHandler AnotherValueChanged;
event EventHandler SomeFlagChanged;
}
Sei antecipadamente que os eventos, embora úteis, raramente seriam usados. Portanto, pensei que faria sentido escondê-los de uma classe de implementação por meio de uma implementação explícita para evitar a confusão do IntelliSense.
c#
interfaces
implementations
Kyle Baran
fonte
fonte
Respostas:
Sim, geralmente é uma forma ruim.
Se o seu IntelliSense estiver muito confuso, sua classe é muito grande. Se sua turma é muito grande, provavelmente está fazendo muitas coisas e / ou mal projetada.
Corrija seu problema, não seu sintoma.
fonte
Use o recurso para o que foi planejado. Reduzir a desorganização do espaço para nome não é um deles.
Razões legítimas não são sobre "esconder" ou organização, são para resolver ambigüidades e se especializar. Se você implementar duas interfaces que definem "Foo", a semântica para Foo pode ser diferente. Realmente não é uma maneira melhor de resolver isso, exceto para interfaces explícitas. A alternativa é proibir a implementação de interfaces sobrepostas ou declarar que as interfaces não podem associar semântica (que é apenas uma coisa conceitual). Ambos são más alternativas. Às vezes, a praticidade supera a elegância.
Alguns autores / especialistas consideram esse recurso um recurso (os métodos não fazem parte do modelo de objeto do tipo). Mas, como todos os recursos, em algum lugar, alguém precisa.
Novamente, eu não o usaria para esconder ou organizar. Existem maneiras de esconder membros do intellisense.
fonte
IDisposable.Dispose
goste da ideia de classes em que algo faz, mas receba um nome diferenteClose
, consideraria perfeitamente razoável para uma classe cujo contrato se isenta expressamente de declarar que o código pode criar e abandonar instâncias semDispose
precisar usar a implementação explícita da interface para defina umIDisposable.Dispose
método que não faz nada.Eu posso ser um sinal de código confuso, mas às vezes o mundo real é confuso. Um exemplo do .NET framework é o ReadOnlyColection, que oculta o setter mutante [], Add and Set.
O IE ReadOnlyCollection implementa IList <T>. Veja também minha pergunta para SO há vários anos atrás, quando refleti sobre isso.
fonte
ConcurrentDictionary
, que implementa vários membros deIDictionary<T>
forma explícita para que os consumidores deConcurrentDictionary
A) não os chamem diretamente e B) possam usar métodos que exigem uma implementação,IDictionary<T>
se absolutamente necessário. Por exemplo, os usuários deConcurrentDictionary<T>
devem ligar emTryAdd
vez deAdd
evitar a necessidade de exceções desnecessárias.Add
explicitamente também reduz a desordem.TryAdd
pode fazer qualquer coisaAdd
(Add
é implementado como uma chamada paraTryAdd
, portanto, fornecer ambos seria redundante). No entanto,TryAdd
necessariamente tem um nome / assinatura diferente, portanto, não é possível implementarIDictionary
sem essa redundância. A implementação explícita resolve esse problema corretamente.É uma boa forma de fazê-lo quando o membro não faz sentido no contexto. Por exemplo, se você criar uma coleção somente leitura implementada
IList<T>
delegando a um objeto interno_wrapped
, poderá ter algo como:Aqui temos quatro casos diferentes.
public T this[int index]
é definido por nossa classe e não pela interface e, portanto, obviamente não é uma implementação explícita, embora observe que é semelhante à leitura-gravaçãoT this[int index]
definida na interface, mas é somente leitura.T IList<T>.this[int index]
é explícito porque uma parte (o getter) corresponde perfeitamente à propriedade acima e a outra parte sempre gera uma exceção. Embora seja vital para alguém acessar uma instância desta classe por meio da interface, não faz sentido alguém usá-la através de uma variável do tipo da classe.Da mesma forma, porque
bool ICollection<T>.IsReadOnly
sempre retornará true, é totalmente inútil o código escrito contra o tipo da classe, mas pode ser vital para usá-lo através do tipo da interface e, portanto, nós o implementamos explicitamente.Por outro lado,
public int Count
não é implementado explicitamente porque poderia ser útil para alguém que usa uma instância por meio de seu próprio tipo.Mas com o seu caso "muito raramente usado", eu me inclinaria muito fortemente para não usar uma implementação explícita.
Nos casos em que eu recomendo usar uma implementação explícita, chamar o método por meio de uma variável do tipo da classe seria um erro (tentando usar o setter indexado) ou inútil (verificar um valor que sempre será o mesmo) para ocultar você está protegendo o usuário de código incorreto ou subótimo. Isso é significativamente diferente do código que você acha que provavelmente será usado raramente . Por isso, eu poderia considerar usar o
EditorBrowsable
atributo para ocultar o membro do intellisense, embora eu estivesse cansado disso; o cérebro das pessoas já tem seu próprio software para filtrar o que não lhes interessa.fonte
IsReadOnly
propriedade?