Como dice el título: ¿es una buena práctica documentar las excepciones lanzadas para las interfaces? ¿Existe siquiera una mejor práctica generalmente acordada? Siento que es un detalle de implementación que no debe incluirse en la interfaz de ninguna manera, pero al mismo tiempo siento que es información valiosa que el usuario de la interfaz debe tener.
Si los comentarios como este son una buena práctica es un tema para otra discusión, así que para limitar el alcance de esta pregunta, supongamos que hemos acordado que documentar el código con comentarios como este es una buena práctica. Aquí con 'comentarios como este' me refiero a comentarios de los que puede generar cosas, es decir, documentación o metadatos, y no solo comentarios 'normales'. Los ejemplos incluyen documentación XML, Javadoc y Doxygen.
Ahora bien, ¿cuál de estos ejemplos de C# es la mejor práctica, si se puede llegar a un acuerdo sobre alguna de las mejores prácticas?
Interfaz sin documentación de excepción:
public interface IMyInterface { /// <summary> /// Does something. /// </summary> void DoSomething(); }
Interfaz con documentación de excepción:
public interface IMyInterface { /// <summary> /// Does something. /// </summary> /// <exception cref="System.Exception">Something went wrong.</exception> void DoSomething(); }
Las interfaces son contratos, si parte de ese contrato incluye una situación en la que se lanza una excepción, definitivamente debe incluirla en su documentación. Puede ver ejemplos de excepciones documentadas en interfaces en todo el marco .NET, por ejemplo, IEnumerator
tiene bastantes. (Texto obtenido haciendo clic derecho en una declaración de IEnumerator
y navegando a "vista de metadatos")
public interface IEnumerator { /// <summary> /// Advances the enumerator to the next element of the collection. /// </summary> /// /// <returns> /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. /// </returns> /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority> bool MoveNext(); /// <summary> /// Sets the enumerator to its initial position, which is before the first element in the collection. /// </summary> /// <exception cref="T:System.InvalidOperationException">The collection was modified after the enumerator was created. </exception><filterpriority>2</filterpriority> void Reset(); /// <summary> /// Gets the current element in the collection. /// </summary> /// /// <returns> /// The current element in the collection. /// </returns> /// <filterpriority>2</filterpriority> object Current { get; } }
Una interfaz solo define el contrato de las operaciones a realizar, no cómo se implementan. Considere el siguiente ejemplo:
void Sort(SortOrder order);
Podría tener la tentación de agregar una throws ArgumentNullException if order is null
pero ¿qué sucede si el implementador de la interfaz decide que recibir un valor nulo en SortOrder
significa que debe usar un SortOrder
predeterminado? (decisión equivocada pero posible). Esta debería ser una decisión válida para el que implementa la interfaz, y si no es una opción para decidir cosas como esta, entonces debería ofrecer una clase base abstracta que arroje la excepción en lugar de una interfaz.
Agregar excepciones a las interfaces es como hacer que las interfaces hereden de la interfaz IDisposable. Estas cosas son detalles de implementación que no deberían deslizarse en la definición de la interfaz.