c# - usados - editor de codigo de visual basic net
La mejor práctica de usar la palabra clave "salir" en C# (9)
Estoy tratando de formalizar el uso de la palabra clave "out" en c # para un proyecto en el que estoy, particularmente con respecto a cualquier método público. Parece que no puedo encontrar las mejores prácticas y me gustaría saber qué es bueno o malo.
A veces veo algunas firmas de métodos que se ven así:
public decimal CalcSomething(Date start, Date end, out int someOtherNumber){}
En este punto, es solo un sentimiento, esto no me sienta bien. Por alguna razón, preferiría ver:
public Result CalcSomething(Date start, Date end){}
donde el resultado es un tipo que contiene un decimal y el someOtherNumber. Creo que esto hace que sea más fácil de leer. Permite que el resultado se extienda o que se agreguen propiedades sin romper el código. También significa que la persona que llama de este método no tiene que declarar un alcance local "algún otro número" antes de llamar. De las expectativas de uso, no todas las personas que llaman estarán interesadas en "algún otro número".
Como contraste, los únicos casos en los que puedo pensar ahora dentro del marco .Net donde los parámetros de "salida" tienen sentido son en métodos como TryParse (). En realidad, hacen que la persona que llama escriba un código más simple, por lo que la persona que llama va a interesarse principalmente en el parámetro de salida.
int i;
if(int.TryParse("1", i)){
DoSomething(i);
}
Estoy pensando que "salir" solo debe usarse si el tipo de retorno es bool y los usos esperados están donde los parámetros de "salida" siempre serán de interés para quien llama, por diseño.
¿Pensamientos?
Esto es lo que la Guía del desarrollador de .NET Framework tiene que decir acerca de los parámetros de salida:
Evite utilizar parámetros de referencia o de salida.
Trabajar con miembros que definen parámetros de referencia o de salida requiere que el desarrollador comprenda los indicadores, las sutiles diferencias entre los tipos de valores y los tipos de referencia, y las diferencias de inicialización entre los parámetros de referencia y de salida.
Pero si los usa:
Coloque todos los parámetros después de todos los parámetros de refinanciación y ref (excluyendo arreglos de parámetros), incluso si esto resulta en una incoherencia en el orden de los parámetros entre sobrecargas .
Esta convención hace que la firma del método sea más fácil de entender.
Hay muy pocos casos en los que usaría. Una de ellas es si su método devuelve dos variables que desde un punto de vista OO no pertenecen juntas a un objeto.
Si, por ejemplo, desea obtener la palabra más común en una cadena de texto, y la 42ª palabra en el texto, puede calcular ambos en el mismo método (tener que analizar el texto solo una vez). Pero para su aplicación, estas informaciones no tienen relación entre sí: necesita la palabra más común para fines estadísticos, pero solo necesita la palabra 42 porque su cliente es fanático de Douglas Adams.
Sí, ese ejemplo es muy artificial, pero no tengo uno mejor ...
Hay una razón por la cual una de las reglas de análisis de código estático (= FxCop) apunta hacia usted cuando utiliza parámetros. Yo diría: solo use cuando realmente lo necesite en escenarios de tipo de interoperabilidad. En todos los demás casos, simplemente no lo use. Pero tal vez ese soy solo yo?
Podría crear una clase de tupla genérica con el fin de devolver múltiples valores. Esta parece ser una solución decente, pero no puedo evitar sentir que pierdes un poco de legibilidad al devolver ese tipo genérico (El Result
no es mejor en ese sentido).
Un punto importante, sin embargo, que James Curran también señaló, es que el compilador impone una asignación del valor. Este es un patrón general que veo en C #, que debe indicar ciertas cosas explícitamente, para obtener un código más legible. Otro ejemplo de esto es la palabra clave override que no tiene en Java.
Si su resultado es más complejo que un valor único, debe, si es posible, crear un objeto de resultado. Las razones por las que tengo que decir esto?
El resultado completo está encapsulado. Es decir, tiene un paquete único que informa el código del resultado completo de CalcSomething. En lugar de tener un código externo que interprete el significado del valor de retorno decimal, puede nombrar las propiedades de su valor de retorno anterior, su valor de SomeOtherNumber, etc.
Puede incluir indicadores de éxito más complejos. La llamada de función que escribió podría generar una excepción si el final es anterior al inicio, pero el lanzamiento de excepción es la única forma de informar errores. Al usar un objeto de resultado, puede incluir un valor booleano o "Correcto" enumerado, con informes de errores apropiados.
Puede retrasar la ejecución del resultado hasta que realmente examine el campo "resultado". Es decir, la ejecución de cualquier computación no necesita hacerse hasta que use los valores.
Su enfoque es mejor que fuera, porque puede "encadenar" llamadas de esa manera:
DoSomethingElse(DoThing(a,b).Result);
Opuesto a
DoThing(a, out b);
DoSomethingElse(b);
Los métodos TryParse implementados con "out" fueron un error, IMO. Esos habrían sido muy convenientes en las cadenas.
Una ventaja de out
es que el compilador verificará que CalcSomething
de hecho asigne un valor a someOtherNumber
. No verificará que el campo de algún otro valor tenga un valor.
Mantente alejado de out
. Está ahí como una conveniencia de bajo nivel. Pero a un alto nivel, es una anti-técnica.
int? i = Util.TryParseInt32("1");
if(i == null)
return;
DoSomething(i);
Si incluso ha visto y trabajado con el espacio de nombres MS System.Web.Security
MembershipProvider
public abstract MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);
Necesitarás un cubo. Este es un ejemplo de una clase que rompe muchos paradigmas de diseño. ¡Horrible!
El hecho de que el lenguaje no tenga parámetros no significa que deba usarse. por ejemplo, goto
El uso de out Se parece más a Dev, ya sea que era perezoso para crear un tipo o quería probar una función de idioma. Incluso el ejemplo de MostCommonAnd42ndWord
completamente artificial arriba usaría List o un nuevo tipo contrivedresult con 2 propiedades.
Las únicas buenas razones que he visto en las explicaciones anteriores fueron en escenarios de interoperabilidad cuando se ven obligados a hacerlo. Suponiendo que es una declaración válida.